vue-pdf實現預覽pdf並使用C-Lodop實現列印功能

来源:https://www.cnblogs.com/feng-xl/archive/2022/09/16/16700052.html
-Advertisement-
Play Games

本人的工作項目中,需求是: 點擊“列印”按鈕,打開pdf預覽彈出框,彈出框有:頭部選擇列印模板、列印方式、印表機,都是下拉選擇框;中部是pdf預覽塊;底部是確定列印。 準備工作: 預覽pdf,後端介面返回了pdf預覽地址,可線上直接打開。vue-pdf插件可以滿足需求。 選擇方式如果選擇本地列印,下 ...


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

  點擊“列印”按鈕,打開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/[email protected]/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
    }

  完畢。歡迎指出。


您的分享是我們最大的動力!

-Advertisement-
Play Games
更多相關文章
  • ​ 回顧數據倉庫的發展歷程,大致可以將其分為幾個階段:萌芽探索到全企業集成時代、企業數據集成時代、混亂時代--"數據倉庫之父"間的論戰、理論模型確認時代以及數據倉庫產品百家爭鳴時代。 數據倉庫理論發展歷程 上世紀70年代,IBM的E.F.Codd等人提出關係型資料庫後,MIT的研究員提出單獨構建分析 ...
  • redis集群的搭建 redis集群的三種模式 主從複製 哨兵模式 cluster集群 redis-cluster集群的搭建(在一臺linux中搭建,三主三從) 下載安裝redis5.0.3 cd /opt 下載redis安裝包 wget http://download.redis.io/relea ...
  • Appuploader可以輔助在Windows、linux或mac系統直接申請iOS證書p12,及上傳ipa到App Store,最方便在Windows開發上架沒有蘋果Mac電腦的開發者!配合本教程使用,可以快速掌握如何真機測試及上架! 點擊蘋果證書 按鈕 點擊新增 ​ 輸入證書密碼,名稱 這個密碼 ...
  • 移動端中的元素內容超出時,對容器設置overflow-x: auto就可以通過手勢水平移動。但是 PC 端只能通過滑鼠滾輪上下滑動,而不能水平移動。 只需要給元素添加一個監聽滑鼠滾輪事件,上下滑動時修改其 scrollLeft 屬性值就可以實現。直接貼上代碼: <div class="horizon ...
  • 好家伙, 我的飛機大戰部署上線了 胖虎的飛機大戰 感興趣的可以去玩一下 (怕有人接受不了這個背景,我還貼心的準備切換背景按鈕,然而這並沒有什麼用) 現在,我們停下腳步,重新審視這個游戲 現在基本的框架都弄出來了,敵機,英雄,子彈,分數,生命 但是,這個“游戲“有個非常致命的問題, 他不好玩,(不好玩 ...
  • 本文分別使用 SFC(模板方式)和 tsx 方式對 Element Plus *el-menu* 組件進行二次封裝,實現配置化的菜單,有了配置化的菜單,後續便可以根據路由動態渲染菜單。 ...
  • vue3中,新增了 defineComponent ,它並沒有實現任何的邏輯,只是把接收的 Object 直接返回,它的存在是完全讓傳入的整個對象獲得對應的類型,它的存在就是完全為了服務 TypeScript 而存在的。 我都知道普通的組件就是一個普通的對象,既然是一個普通的對象,那自然就不會獲得自 ...
  • 這裡給大家分享我在網上總結出來的一些知識,希望對大家有所幫助 一、前言 入職的第一個需求是跟著一位前端大佬一起完成的一個活動項目。 由於是一起開發,當然不會放過閱讀大佬的代碼的機會。 因為我的頁面中需要使用到倒計時功能,發現大佬的已經寫了個現成的倒計時組件,於是直接就拿過來用了。 傳個參數就實現了功 ...
一周排行
    -Advertisement-
    Play Games
  • 移動開發(一):使用.NET MAUI開發第一個安卓APP 對於工作多年的C#程式員來說,近來想嘗試開發一款安卓APP,考慮了很久最終選擇使用.NET MAUI這個微軟官方的框架來嘗試體驗開發安卓APP,畢竟是使用Visual Studio開發工具,使用起來也比較的順手,結合微軟官方的教程進行了安卓 ...
  • 前言 QuestPDF 是一個開源 .NET 庫,用於生成 PDF 文檔。使用了C# Fluent API方式可簡化開發、減少錯誤並提高工作效率。利用它可以輕鬆生成 PDF 報告、發票、導出文件等。 項目介紹 QuestPDF 是一個革命性的開源 .NET 庫,它徹底改變了我們生成 PDF 文檔的方 ...
  • 項目地址 項目後端地址: https://github.com/ZyPLJ/ZYTteeHole 項目前端頁面地址: ZyPLJ/TreeHoleVue (github.com) https://github.com/ZyPLJ/TreeHoleVue 目前項目測試訪問地址: http://tree ...
  • 話不多說,直接開乾 一.下載 1.官方鏈接下載: https://www.microsoft.com/zh-cn/sql-server/sql-server-downloads 2.在下載目錄中找到下麵這個小的安裝包 SQL2022-SSEI-Dev.exe,運行開始下載SQL server; 二. ...
  • 前言 隨著物聯網(IoT)技術的迅猛發展,MQTT(消息隊列遙測傳輸)協議憑藉其輕量級和高效性,已成為眾多物聯網應用的首選通信標準。 MQTTnet 作為一個高性能的 .NET 開源庫,為 .NET 平臺上的 MQTT 客戶端與伺服器開發提供了強大的支持。 本文將全面介紹 MQTTnet 的核心功能 ...
  • Serilog支持多種接收器用於日誌存儲,增強器用於添加屬性,LogContext管理動態屬性,支持多種輸出格式包括純文本、JSON及ExpressionTemplate。還提供了自定義格式化選項,適用於不同需求。 ...
  • 目錄簡介獲取 HTML 文檔解析 HTML 文檔測試參考文章 簡介 動態內容網站使用 JavaScript 腳本動態檢索和渲染數據,爬取信息時需要模擬瀏覽器行為,否則獲取到的源碼基本是空的。 本文使用的爬取步驟如下: 使用 Selenium 獲取渲染後的 HTML 文檔 使用 HtmlAgility ...
  • 1.前言 什麼是熱更新 游戲或者軟體更新時,無需重新下載客戶端進行安裝,而是在應用程式啟動的情況下,在內部進行資源或者代碼更新 Unity目前常用熱更新解決方案 HybridCLR,Xlua,ILRuntime等 Unity目前常用資源管理解決方案 AssetBundles,Addressable, ...
  • 本文章主要是在C# ASP.NET Core Web API框架實現向手機發送驗證碼簡訊功能。這裡我選擇是一個互億無線簡訊驗證碼平臺,其實像阿裡雲,騰訊雲上面也可以。 首先我們先去 互億無線 https://www.ihuyi.com/api/sms.html 去註冊一個賬號 註冊完成賬號後,它會送 ...
  • 通過以下方式可以高效,並保證數據同步的可靠性 1.API設計 使用RESTful設計,確保API端點明確,並使用適當的HTTP方法(如POST用於創建,PUT用於更新)。 設計清晰的請求和響應模型,以確保客戶端能夠理解預期格式。 2.數據驗證 在伺服器端進行嚴格的數據驗證,確保接收到的數據符合預期格 ...