本人的工作項目中,需求是: 點擊“列印”按鈕,打開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 }
完畢。歡迎指出。