ICode9

精准搜索请尝试: 精确搜索
首页 > 其他分享> 文章详细

vue-pdf实现预览pdf并使用C-Lodop实现打印功能

2022-09-16 16:30:26  阅读:281  来源: 互联网

标签:vue return const 打印 LODOP pdf match Lodop


本人的工作项目中,需求是:

  点击“打印”按钮,打开pdf预览弹出框,弹出框有:头部选择打印模板、打印方式、打印机,都是下拉选择框;中部是pdf预览块;底部是确定打印。

 

准备工作:

  预览pdf,后端接口返回了pdf预览地址,可在线直接打开。vue-pdf插件可以满足需求。

  选择方式如果选择本地打印,下拉列表是该电脑所连接的所有打印设备,且连接打印机打印出pdf内容。我司花钱购买了C-Lodop商用产品,用这个打印控件可以满足需求。官方地址:http://www.lodop.net/

 

直接上关键代码,温馨提示:预览pdf在最后

  一、由于项目中许多地方会用到该打印预览弹框,封装一个print.vue组件文件,核心代码:

  1、打印机下拉资源获取:

    首先是:LodopFuncs.js文件,官网可以下载,根据本人工作需求情况,做了一些改动。

//= =本JS是加载Lodop插件或Web打印服务CLodop/Lodop7的综合示例,可直接使用,建议理解后融入自己程序==
// 资料链接:http://www.lodop.net/

import message from 'ant-design-vue/es/message'
import modal from 'ant-design-vue/es/modal'

let CLodopIsLocal, CLodopJsState

//= =判断是否需要CLodop(那些不支持插件的浏览器):==
function needCLodop () {
  try {
    const ua = navigator.userAgent
    if (ua.match(/Windows\sPhone/i)) return true
    if (ua.match(/iPhone|iPod|iPad/i)) return true
    if (ua.match(/Android/i)) return true
    if (ua.match(/Edge\D?\d+/i)) return true

    const verTrident = ua.match(/Trident\D?\d+/i)
    const verIE = ua.match(/MSIE\D?\d+/i)
    let verOPR = ua.match(/OPR\D?\d+/i)
    let verFF = ua.match(/Firefox\D?\d+/i)
    const x64 = ua.match(/x64/i)
    if ((!verTrident) && (!verIE) && (x64)) return true
    else if (verFF) {
      verFF = verFF[0].match(/\d+/)
      if ((verFF[0] >= 41) || (x64)) return true
    } else if (verOPR) {
      verOPR = verOPR[0].match(/\d+/)
      if (verOPR[0] >= 32) return true
    } else if ((!verTrident) && (!verIE)) {
      let verChrome = ua.match(/Chrome\D?\d+/i)
      if (verChrome) {
        verChrome = verChrome[0].match(/\d+/)
        if (verChrome[0] >= 41) return true
      }
    }
    return false
  } catch (err) {
    return true
  }
}

// 加载CLodop时用双端口(http是8000/18000,而https是8443/8444)以防其中某端口被占,
// 主JS文件名“CLodopfuncs.js”是固定名称,其内容是动态的,与其链接的打印环境有关:
function loadCLodop () {
  if (CLodopJsState === 'loading' || CLodopJsState === 'complete') return
  CLodopJsState = 'loading'
  const head = document.head || document.getElementsByTagName('head')[0] || document.documentElement
  const JS1 = document.createElement('script')
  const JS2 = document.createElement('script')
  console.log(window.location.protocol === 'https:', 'https')

  // if (window.location.protocol === 'https:') {
  //   JS1.src = 'https://localhost.lodop.net:8443/CLodopfuncs.js'
  //   JS2.src = 'https://localhost.lodop.net:8444/CLodopfuncs.js'
  // } else {
  JS1.src = 'http://localhost:8000/CLodopfuncs.js'
  JS2.src = 'http://localhost:18000/CLodopfuncs.js?priority=1'
  // }
  JS1.onload = JS2.onload = function () { CLodopJsState = 'complete' }
  JS1.onerror = JS2.onerror = function (evt) { CLodopJsState = 'complete' }
  head.insertBefore(JS1, head.firstChild)
  head.insertBefore(JS2, head.firstChild)
  CLodopIsLocal = !!((JS1.src + JS2.src).match(/\/\/localho|\/\/127.0.0./i))
}

/**
 * @description: 提示下载
 * @param {String} href 下载地址
 * @return {*}
 */
function modalOfDownload (href) {
  const content = '打印控件需要升级!点击【确定】下载并执行安装'
  modal.confirm({
    content,
    onOk () {
      const a = document.createElement('a')
      a.href = 'https://test-xxxxxxxxx.cos.ap-xxx.xxx.com/kits/' + href
      document.body.appendChild(a)
      a.click()
      a.remove()
    }
  })
}

/**
 * @description: 获取LODOP对象主过程,判断是否安装、需否升级
 * @return {Object} { state: 3 , LODOP,   message: '' } state: 1未安装、2未运行、3具备打印条件
 */
function getLodop () {
  let LODOP

  try {
    if (needCLodop()) {
      try {
        LODOP = window.getCLodop()
      } catch (err) {}

      console.log('CLodopJsState', CLodopJsState)
      if (!LODOP && CLodopJsState !== 'complete') {
        if (CLodopJsState === 'loading') {
          message.info('网页还没下载完毕,请稍等一下再操作.')
        } else {
          message.info('未曾加载Lodop主JS文件,请先调用loadCLodop过程.')
        }
        return { state: 0 }
      }

      // 不存在则提示安装
      if (!LODOP) {
        if (CLodopIsLocal) {
          return { state: 2, message: '此前已安装过,点击【运行】直接再次启动' }
        } else {
          return { state: 1, message: 'Web打印服务CLodop未安装启动,点击下载执行并安装' }
        }
      } else {
        // 判断版本
        const isWinIE = (/MSIE/i.test(navigator.userAgent)) || (/Trident/i.test(navigator.userAgent))
        const isWinIE64 = isWinIE && (/x64/i.test(navigator.userAgent))
        if (window.CLODOP.CVERSION < '4.1.5.5') {
          const exeHref = isWinIE64 ? 'install_lodop64.exe' : 'install_lodop32.exe'
          modalOfDownload(exeHref)
          return { state: 0 }
        }
      }
    }

    if (LODOP) {
      //= ==如下空白位置适合调用统一功能(如注册语句、语言选择等):=======================
      LODOP.SET_LICENSES('', '7***************9', '', '')
      console.log('SET_LICENSES执⾏了')

      // LODOP.SET_LICENSES('', '13*******39', 'ED*******10', 'D6**********8')

      //= ==============================================================================
      return { state: 3, LODOP, message: '具备打印条件' }
    }
  } catch (err) {
    console.error('getLodop出错:' + err)
  }
}

if (needCLodop()) { loadCLodop() } // 开始加载
export { getLodop }

  项目中引入:

import { getLodop } from '@/utils/LodopFuncs'

  methods方法中使用:

  /**
     * @description: 获取本地已连接打印机
     */
    getLocalPrinter () {
      const lop = getLodop()
      console.log('lop对象', lop)

      if (!lop.state) return

      if ([1, 2].includes(lop.state)) {
        this.initPrinterOptions()
        this.showPlugin = true
        return
      }

      this.LODOP = lop.LODOP
      const counter = this.LODOP.GET_PRINTER_COUNT() // 获取打印机个数
      console.log(counter, '获取打印机个数')

      var printNameList = []
      for (let i = 0; i < counter; i++) {
        const printerName = this.LODOP.GET_PRINTER_NAME(i)
        printNameList.push({ printerName, id: printerName })
      }
      this.printerOptions = JSON.parse(JSON.stringify(printNameList)) // 打印机下拉列表资源
    }

  2、连接打印机,打印出pdf在线地址的内容:

    (1)上面的打印机资源完成赋值以后,下拉选择你需要打印的打印机,并记住选择的id。

    (2)点击弹框的确定,开始打印,执行方法如下:

  /**
     * @description: 本地打印
     */
    doLocalPrint () {
      console.log(this.LODOP.PRINT_INIT, 'lodop是否运行')
      if (!this.LODOP.PRINT_INIT) {
        // 考虑中途卸载或者停用的情况,再提示打印插件下载,弹出插件下载提示框
        this.initPrinterOptions()
        this.showPlugin = true
        return
      }

      // 开启懒加载
      this.loading.confirm = true
      this.$message.loading('准备打印中...', 0)

      // 打印初始化配置
      this.LODOP.PRINT_INIT(`${this.title}_${dateUtils.format('yyyyMMdd')}`)
      this.LODOP.SET_PRINTER_INDEX(this.dataForm.printerId)

      // 循环打印 【我们项目存在批量打印,所以需要一张张加进去再打印】
      for (let i = 0; i < this.printList.length; i++) {
        const pdfIm = this.printList[i]
        const pageWidth = pdfIm.pageWidth ? Math.floor(pdfIm.pageWidth / 1.1756) : 2050
        console.log(pageWidth, '本地打印宽度')
        this.LODOP.SET_PRINT_PAGESIZE(1, pageWidth, pdfIm.pageHeight) // http://www.lodop.net/demolist/PrintSample5.html
        this.LODOP.ADD_PRINT_PDF(0, 0, '100%', '100%', this.demoDownloadPDF(pdfIm.urls)) // (Top,Left,Width,Height,strURLorContent) 上边距/左边距/
        // this.LODOP.ADD_PRINT_HTM(0, '5mm') // http://www.lodop.net/demolist/PrintSample46.html
        this.LODOP.PRINT() // 执行打印
      }

      this.$message.success('单据打印中...')
      // 关闭处理
      this.loading.confirm = false
    },

  demoDownloadPDF (url) {
      if (!/^https?:/i.test(url)) return
      let xhr = null
      if (window.XMLHttpRequest) xhr = new XMLHttpRequest()
      else xhr = new window.ActiveXObject('MSXML2.XMLHTTP')
      xhr.open('GET', url, false) // 同步方式
      if (xhr.overrideMimeType) {
        try {
          xhr.responseType = 'arraybuffer'
          var arrybuffer = true
        } catch (err) {
          xhr.overrideMimeType('text/plain; charset=x-user-defined')
        }
      }
      xhr.send(null)
      var data = xhr.response || xhr.responseBody
      let dataArray = null
      if (typeof Uint8Array !== 'undefined') {
        if (arrybuffer) dataArray = new Uint8Array(data)
        else {
          dataArray = new Uint8Array(data.length)
          for (var i = 0; i < dataArray.length; i++) {
            dataArray[i] = data.charCodeAt(i)
          }
        }
      } else dataArray = window.VBS_BinaryToArray(data).toArray() // 兼容IE低版本
      return this.demoGetBASE64(dataArray)
    },
    demoGetBASE64 (dataArray) {
      var digits = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/='
      var strData = ''
      for (var i = 0, ii = dataArray.length; i < ii; i += 3) {
        if (isNaN(dataArray[i])) break
        var b1 = dataArray[i] & 0xff
        var b2 = dataArray[i + 1] & 0xff
        var b3 = dataArray[i + 2] & 0xff
        var d1 = b1 >> 2
        var d2 = ((b1 & 3) << 4) | (b2 >> 4)
        var d3 = i + 1 < ii ? ((b2 & 0xf) << 2) | (b3 >> 6) : 64
        var d4 = i + 2 < ii ? b3 & 0x3f : 64
        strData +=
          digits.substring(d1, d1 + 1) +
          digits.substring(d2, d2 + 1) +
          digits.substring(d3, d3 + 1) +
          digits.substring(d4, d4 + 1)
      }
      return strData
    }

  3、vue-pdf预览:

    (1)页面元素核心代码:

    <!-- pdf预览 -->
      <div class="preview" v-loading="loading.preview">
        <template v-if="pdfList.length">
          <template v-for="pdfItem in pdfList">
            <pdf v-for="(pPage, pIdx) in pdfItem.numPages" :key="pIdx + pdfItem.id" :page="pPage" :src="pdfItem.src" />
          </template>
        </template>
        <empty v-else text="暂无预览结果" />
      </div>

    (2)script的data部分:

      导入:

import pdf from 'vue-pdf'

      关键变量:

printList: [], // 打印的数据列表
pdfList: [], // pdf文件列表

    (3)拿到后端返回的数据后,转化为vue-pdf插件可用数据:

// 请求数据api
const { res } = await this.$caputured(this.$api[this.config.apiName], params)
 if (res) {
    this.printList = res.data
    this.setPdfSrc(res.data)
 } else {
    this.pdfList = [] // 清除pdf列表
    this.printList = [] // 清除pdf列表
 }
   /**
     * @description: 设置pdf
     */
    async setPdfSrc (pdfUrls) {
      const list = []
      for (let i = 0; i < pdfUrls.length; i++) {
        const loadingTask = pdf.createLoadingTask({
          url: pdfUrls[i].urls, // pdf地址
          cMapUrl: 'https://cdn.jsdelivr.net/npm/pdfjs-dist@2.2.228/cmaps/', // 加载字体包
          cMapPacked: true
        })
        await loadingTask.promise.then((p) => {
          list.push({
            id: pdfUrls[i].id,
            src: loadingTask,
            numPages: p.numPages
          })
        })
      }
      this.pdfList = list
    }

  4、其他情况,弹出的提示框按钮需求,有运行c-lodop和下载:

<a-button class="margin-right-8" @click="loadClodop">运行</a-button>
<a-button type="primary" @click="downloadClodop">下载并安装</a-button>

    /**
     * @description: 运行
     */
    loadClodop () {
      // 查看本机是否安装(控件或web打印服务)
      const lop = getLodop()
      if (lop.state === 1) this.$message.warn(lop.message, 3)
      else if (lop.state === 2) {
        // 手动触发运行
        const a = document.createElement('a')
        a.href = 'CLodop.protocol:setup'
        a.target = '_self'
        document.body.appendChild(a)
        a.click()
        a.remove()
        this.showPlugin = false
      }
    },


    /**
     * @description: 下载
     */
    downloadClodop () {
      const a = document.createElement('a')
      a.href = '下载地址'
      document.body.appendChild(a)
      a.click()
      this.showPlugin = false
    }

  完毕。欢迎指出。

标签:vue,return,const,打印,LODOP,pdf,match,Lodop
来源: https://www.cnblogs.com/feng-xl/p/16700052.html

本站声明: 1. iCode9 技术分享网(下文简称本站)提供的所有内容,仅供技术学习、探讨和分享;
2. 关于本站的所有留言、评论、转载及引用,纯属内容发起人的个人观点,与本站观点和立场无关;
3. 关于本站的所有言论和文字,纯属内容发起人的个人观点,与本站观点和立场无关;
4. 本站文章均是网友提供,不完全保证技术分享内容的完整性、准确性、时效性、风险性和版权归属;如您发现该文章侵犯了您的权益,可联系我们第一时间进行删除;
5. 本站为非盈利性的个人网站,所有内容不会用来进行牟利,也不会利用任何形式的广告来间接获益,纯粹是为了广大技术爱好者提供技术内容和技术思想的分享性交流网站。

专注分享技术,共同学习,共同进步。侵权联系[81616952@qq.com]

Copyright (C)ICode9.com, All Rights Reserved.

ICode9版权所有