|
@@ -0,0 +1,219 @@
|
|
|
+import type { PrintOption, PrintPdfOption } from './types'
|
|
|
+export const printContainerId = 'custom-printer-container'
|
|
|
+export const printFrameId = 'custom-printer-iframe'
|
|
|
+export const printingClass = 'custom-printing'
|
|
|
+
|
|
|
+/**
|
|
|
+ * 创建并获取打印容器
|
|
|
+ */
|
|
|
+export function getPrintContainer(): Element {
|
|
|
+ const container = document.getElementById(printContainerId)
|
|
|
+ if (container) {
|
|
|
+ return container
|
|
|
+ }
|
|
|
+ const elem = document.createElement('div')
|
|
|
+ elem.id = printContainerId
|
|
|
+ document.body.appendChild(elem)
|
|
|
+ return elem
|
|
|
+}
|
|
|
+
|
|
|
+/**
|
|
|
+ * 打印
|
|
|
+ */
|
|
|
+export function doPrint(option: PrintOption) {
|
|
|
+ const $html = document.querySelector('html')
|
|
|
+ if ($html) {
|
|
|
+ $html.classList.add(printingClass)
|
|
|
+ // 打印设置
|
|
|
+ const elem = document.createElement('style')
|
|
|
+ elem.setAttribute('type', 'text/css')
|
|
|
+ elem.setAttribute('media', 'print')
|
|
|
+ elem.innerHTML = getOptionCss(option)
|
|
|
+ document.body.appendChild(elem)
|
|
|
+ // 修改页面标题
|
|
|
+ const title = document.title
|
|
|
+ if (option.title != null && option.title !== '') {
|
|
|
+ document.title = option.title
|
|
|
+ }
|
|
|
+ // 打印
|
|
|
+ ;(window as any).print(option.options)
|
|
|
+ // 打印结束
|
|
|
+ $html.classList.remove(printingClass)
|
|
|
+ document.body.removeChild(elem)
|
|
|
+ // 恢复页面标题
|
|
|
+ if (option.title != null) {
|
|
|
+ document.title = title
|
|
|
+ }
|
|
|
+ }
|
|
|
+}
|
|
|
+
|
|
|
+/**
|
|
|
+ * 在子窗口中打印
|
|
|
+ */
|
|
|
+export function doPrintOnFrame(opt: PrintOption) {
|
|
|
+ const pFrame = getPrintFrame()
|
|
|
+ const pWin = pFrame.contentWindow
|
|
|
+ if (!pWin) {
|
|
|
+ return
|
|
|
+ }
|
|
|
+ pWin.focus()
|
|
|
+ const pDoc = pFrame.contentDocument || pWin.document
|
|
|
+ if (!pDoc) {
|
|
|
+ return
|
|
|
+ }
|
|
|
+ //
|
|
|
+ const container = getPrintContainer()
|
|
|
+ Array.from(container.querySelectorAll('input[type="text"], input[type="number"]')).forEach((el: any) => {
|
|
|
+ el.setAttribute('value', el.value)
|
|
|
+ })
|
|
|
+ //
|
|
|
+ pDoc.open()
|
|
|
+ const printOption = opt.options ? `JSON.parse('${JSON.stringify(opt.options)}')` : ''
|
|
|
+ const optHtml = `
|
|
|
+ <style type="text/css" media="print">
|
|
|
+ ${getOptionCss(opt)}
|
|
|
+ </style>
|
|
|
+ <script>
|
|
|
+ const $html = document.querySelector('html');
|
|
|
+ if($html && $html.classList && $html.classList.add) {
|
|
|
+ $html.classList.add('${printingClass}');
|
|
|
+ }
|
|
|
+ window.onload = function() {
|
|
|
+ if(${opt.title == null ? 0 : 1}) {
|
|
|
+ document.title = '${opt.title}';
|
|
|
+ }
|
|
|
+ window.print(${printOption});
|
|
|
+ window.parent.postMessage('customPrintDone_${opt.printId}', '*');
|
|
|
+ };
|
|
|
+ </script>
|
|
|
+ `
|
|
|
+ const html = document.querySelector('html')?.outerHTML || ''
|
|
|
+ const content = html
|
|
|
+ .replace(/<script/g, '<textarea style="display:none;" ')
|
|
|
+ .replace(/<\/script>/g, '</textarea>')
|
|
|
+ .replace(/<\/html>/, optHtml + '</html>')
|
|
|
+ pDoc.write('<!DOCTYPE html>' + content)
|
|
|
+ pDoc.close()
|
|
|
+ return pWin
|
|
|
+}
|
|
|
+
|
|
|
+/**
|
|
|
+ * 创建并获取打印子窗口
|
|
|
+ */
|
|
|
+export function getPrintFrame(): HTMLIFrameElement {
|
|
|
+ removePrintFrame()
|
|
|
+ const elem = document.createElement('iframe')
|
|
|
+ elem.id = printFrameId
|
|
|
+ elem.style.width = '0px'
|
|
|
+ elem.style.height = '0px'
|
|
|
+ elem.style.position = 'fixed'
|
|
|
+ elem.style.visibility = 'hidden'
|
|
|
+ document.body.appendChild(elem)
|
|
|
+ elem.focus()
|
|
|
+ return elem
|
|
|
+}
|
|
|
+
|
|
|
+/**
|
|
|
+ * 移除打印子窗口
|
|
|
+ */
|
|
|
+export function removePrintFrame() {
|
|
|
+ const pFrame = document.getElementById(printFrameId)
|
|
|
+ if (pFrame && pFrame.parentNode) {
|
|
|
+ pFrame.parentNode.removeChild(pFrame)
|
|
|
+ }
|
|
|
+}
|
|
|
+
|
|
|
+/**
|
|
|
+ * 生成打印设置的样式
|
|
|
+ */
|
|
|
+export function getOptionCss(opt: PrintOption) {
|
|
|
+ const css = ['@page {']
|
|
|
+ if (opt.margin != null && opt.margin !== '') {
|
|
|
+ const v = typeof opt.margin === 'number' ? opt.margin + 'px' : opt.margin
|
|
|
+ css.push(`margin: ${v};`)
|
|
|
+ }
|
|
|
+ if (opt.direction != null && opt.direction !== '') {
|
|
|
+ css.push(`size: ${opt.direction};`)
|
|
|
+ }
|
|
|
+ if (opt.orientation != null && opt.orientation !== '') {
|
|
|
+ css.push(`page-orientation: ${opt.orientation};`)
|
|
|
+ }
|
|
|
+ css.push('}')
|
|
|
+ return css.join(' ')
|
|
|
+}
|
|
|
+
|
|
|
+/**
|
|
|
+ * 合并打印方法参数
|
|
|
+ * @param options 参数
|
|
|
+ * @param userOptions 自定义参数
|
|
|
+ */
|
|
|
+export function mergeOptions(options?: any, userOptions?: any) {
|
|
|
+ if (options == null) {
|
|
|
+ return userOptions
|
|
|
+ }
|
|
|
+ return Object.assign({}, options, userOptions)
|
|
|
+}
|
|
|
+
|
|
|
+/**
|
|
|
+ * usePrinter
|
|
|
+ */
|
|
|
+export function usePrinter(done: () => void) {
|
|
|
+ const printId = Date.now() + ''
|
|
|
+ const onMessage = (e: MessageEvent<any>) => {
|
|
|
+ if (e.data === `customPrintDone_${printId}`) {
|
|
|
+ removePrintFrame()
|
|
|
+ done && done()
|
|
|
+ }
|
|
|
+ }
|
|
|
+ window.addEventListener('message', onMessage)
|
|
|
+ onBeforeUnmount(() => {
|
|
|
+ window.removeEventListener('message', onMessage)
|
|
|
+ })
|
|
|
+ return { printId }
|
|
|
+}
|
|
|
+
|
|
|
+/**
|
|
|
+ * 打印 pdf
|
|
|
+ * @param option 打印参数
|
|
|
+ */
|
|
|
+export function printPdf(option: PrintPdfOption) {
|
|
|
+ const pFrame: any = getPrintFrame()
|
|
|
+ pFrame.onload = () => {
|
|
|
+ const url = pFrame.getAttribute('src')
|
|
|
+ if (url) {
|
|
|
+ pFrame.focus()
|
|
|
+ pFrame.contentWindow && pFrame.contentWindow.print(option.options)
|
|
|
+ option.done && option.done()
|
|
|
+ URL.revokeObjectURL(url)
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ // 开始打印
|
|
|
+ const doPrint = (buffer: ArrayBuffer) => {
|
|
|
+ const blob = new window.Blob([buffer], { type: 'application/pdf' })
|
|
|
+ // if (window.navigator && window.navigator['msSaveOrOpenBlob']) {
|
|
|
+ // window.navigator['msSaveOrOpenBlob'](blob, 'print.pdf')
|
|
|
+ // return
|
|
|
+ // }
|
|
|
+ pFrame.setAttribute('src', window.URL.createObjectURL(blob))
|
|
|
+ }
|
|
|
+
|
|
|
+ // 请求 pdf 数据
|
|
|
+ if (option.arraybuffer) {
|
|
|
+ doPrint(option.arraybuffer)
|
|
|
+ return
|
|
|
+ }
|
|
|
+ if (option.url) {
|
|
|
+ const req = new window.XMLHttpRequest()
|
|
|
+ req.open('GET', option.url, true)
|
|
|
+ req.responseType = 'arraybuffer'
|
|
|
+ req.onload = () => {
|
|
|
+ if ([200, 201].indexOf(req.status) !== -1) {
|
|
|
+ doPrint(req.response)
|
|
|
+ return
|
|
|
+ }
|
|
|
+ option.error && option.error(req.status, req.statusText)
|
|
|
+ }
|
|
|
+ req.send()
|
|
|
+ }
|
|
|
+}
|