83 lines
3.8 KiB
TypeScript
83 lines
3.8 KiB
TypeScript
import { nextTick } from 'vue'
|
|
|
|
const printStyles = `
|
|
@page { size: A4 landscape; margin: 10mm; }
|
|
body { margin: 0; color: #111; font: 10pt/1.4 Arial, "Microsoft YaHei", sans-serif; }
|
|
h1 { margin: 0 0 12px; font-size: 16pt; }
|
|
.detail-summary { display: grid; grid-template-columns: repeat(3, minmax(0, 1fr)); margin-bottom: 16px; border-top: 1px solid #aaa; border-left: 1px solid #aaa; }
|
|
.detail-summary > div { display: flex; gap: 8px; padding: 6px; border-right: 1px solid #aaa; border-bottom: 1px solid #aaa; }
|
|
.detail-summary > div > span:first-child { flex-shrink: 0; color: #555; }
|
|
.detail-summary strong { min-width: 0; overflow-wrap: anywhere; }
|
|
table { width: 100%; border-collapse: collapse; table-layout: fixed; font-size: 8pt; }
|
|
caption { margin-bottom: 6px; font-size: 11pt; font-weight: bold; text-align: left; }
|
|
th, td { padding: 4px; border: 1px solid #aaa; vertical-align: top; text-align: left; overflow-wrap: anywhere; }
|
|
th { background: #eee; }
|
|
.cell { white-space: normal; overflow-wrap: anywhere; }
|
|
small { display: block; }
|
|
thead { display: table-header-group; }
|
|
tr { break-inside: avoid; }
|
|
`
|
|
|
|
let printing = false
|
|
|
|
function printDocumentHtml(root: HTMLElement) {
|
|
const summary = root.querySelector('[data-loading-list-print-summary]')
|
|
const items = root.querySelector('[data-loading-list-print-items]')
|
|
const head = items?.querySelector('thead')
|
|
const body = items?.querySelector('tbody')
|
|
if (!summary || !head || !body) throw new Error('清单尚未加载完成,请稍后重试')
|
|
|
|
const title = root.getAttribute('aria-label') || '装柜清单'
|
|
const page = document.implementation.createHTMLDocument(title)
|
|
page.documentElement.lang = 'zh-CN'
|
|
const style = page.createElement('style')
|
|
style.textContent = printStyles
|
|
page.head.append(style)
|
|
const heading = page.createElement('h1')
|
|
heading.textContent = title
|
|
const table = page.createElement('table')
|
|
const caption = page.createElement('caption')
|
|
caption.textContent = '装柜货物明细'
|
|
table.append(caption, head.cloneNode(true), body.cloneNode(true))
|
|
page.body.append(heading, summary.cloneNode(true), table)
|
|
page.body.querySelectorAll('button, input, svg, [hidden], [aria-hidden="true"]').forEach(node => node.remove())
|
|
page.body.querySelectorAll<HTMLElement>('[style]').forEach(node => {
|
|
if (node.style.display === 'none') node.remove()
|
|
else node.removeAttribute('style')
|
|
})
|
|
return `<!doctype html>${page.documentElement.outerHTML}`
|
|
}
|
|
|
|
export async function printLoadingList(root: HTMLElement | null | undefined): Promise<boolean> {
|
|
if (printing) return false
|
|
if (!root) throw new Error('清单尚未加载完成,请稍后重试')
|
|
printing = true
|
|
let frame: HTMLIFrameElement | undefined
|
|
try {
|
|
await nextTick()
|
|
const html = printDocumentHtml(root)
|
|
frame = document.createElement('iframe')
|
|
frame.title = '装柜清单打印'
|
|
frame.setAttribute('aria-hidden', 'true')
|
|
frame.style.cssText = 'position:fixed;left:-10000px;top:0;width:297mm;height:210mm;border:0'
|
|
document.body.append(frame)
|
|
const printDocument = frame.contentDocument
|
|
if (!printDocument) throw new Error('无法创建打印页面,请重试')
|
|
const printFrame = frame
|
|
return await new Promise<boolean>((resolve, reject) => {
|
|
printFrame.addEventListener('load', () => {
|
|
const target = printFrame.contentWindow
|
|
if (!target) { reject(new Error('无法创建打印页面,请重试')); return }
|
|
target.addEventListener('afterprint', () => resolve(true), { once: true })
|
|
try { target.focus(); target.print() } catch (cause) { reject(cause) }
|
|
}, { once: true })
|
|
printDocument.open()
|
|
printDocument.write(html)
|
|
printDocument.close()
|
|
})
|
|
} finally {
|
|
frame?.remove()
|
|
printing = false
|
|
}
|
|
}
|