function escapeHtml(value) {
|
return String(value ?? '')
|
.replaceAll('&', '&')
|
.replaceAll('<', '<')
|
.replaceAll('>', '>')
|
.replaceAll('"', '"')
|
.replaceAll("'", ''')
|
}
|
|
function getReportStyle(meta = {}) {
|
return meta?.reportStyle && typeof meta.reportStyle === 'object' ? meta.reportStyle : {}
|
}
|
|
function getTitleAlignClass(titleAlign) {
|
const alignMap = {
|
left: 'title-left',
|
center: 'title-center',
|
right: 'title-right'
|
}
|
return alignMap[titleAlign] ?? alignMap.center
|
}
|
|
function getTitleLevelClass(titleLevel) {
|
const levelMap = {
|
normal: 'title-normal',
|
strong: 'title-strong',
|
prominent: 'title-prominent'
|
}
|
return levelMap[titleLevel] ?? levelMap.strong
|
}
|
|
function getPageOrientation(reportStyle = {}) {
|
return reportStyle.orientation === 'landscape' ? 'landscape' : 'portrait'
|
}
|
|
function getMetaItems(meta = {}) {
|
return [
|
{ key: 'reportDate', label: '报表日期', value: meta.reportDate ?? '--' },
|
{ key: 'operator', label: '打印人', value: meta.operator ?? '--' },
|
{ key: 'printedAt', label: '打印时间', value: meta.printedAt ?? '--' },
|
{ key: 'count', label: '记录数', value: meta.count ?? '--' }
|
]
|
}
|
|
function getCellText(row, column, index) {
|
if (column?.source === '__sequence__') {
|
return index + 1
|
}
|
return row?.[column?.source] ?? '--'
|
}
|
|
function getAlignClass(column = {}) {
|
const alignMap = {
|
left: 'cell-left',
|
center: 'cell-center',
|
right: 'cell-right'
|
}
|
return alignMap[column.align] ?? alignMap.left
|
}
|
|
export function buildPrintDocumentHtml({ title = '报表', meta = {}, rows = [], columns = [] } = {}) {
|
const reportStyle = getReportStyle(meta)
|
const reportTitle = meta.reportTitle || title
|
const titleClass = `${getTitleAlignClass(reportStyle.titleAlign)} ${getTitleLevelClass(reportStyle.titleLevel)}`
|
const orientation = getPageOrientation(reportStyle)
|
const showBorder = reportStyle.showBorder !== false
|
const metaItems = getMetaItems(meta)
|
const tableWrapClass = showBorder ? 'report-table-wrap' : 'report-table-wrap report-table-wrap-borderless'
|
const cellClassName = showBorder ? 'cell-bordered' : 'cell-borderless'
|
|
const headerHtml = columns
|
.map(
|
(column) =>
|
`<th class="${getAlignClass(column)} ${cellClassName}">${escapeHtml(column.label ?? '--')}</th>`
|
)
|
.join('')
|
|
const bodyHtml =
|
rows.length > 0
|
? rows
|
.map((row, index) => {
|
const cells = columns
|
.map(
|
(column) =>
|
`<td class="${getAlignClass(column)} ${cellClassName}">${escapeHtml(getCellText(row, column, index))}</td>`
|
)
|
.join('')
|
return `<tr>${cells}</tr>`
|
})
|
.join('')
|
: `<tr><td colspan="${Math.max(columns.length, 1)}" class="empty-cell">暂无打印数据</td></tr>`
|
|
const metaHtml = metaItems
|
.map(
|
(item) =>
|
`<div class="report-meta-item"><span class="report-meta-label">${escapeHtml(item.label)}</span><span class="report-meta-value">${escapeHtml(item.value)}</span></div>`
|
)
|
.join('')
|
|
return `<!DOCTYPE html>
|
<html lang="zh-CN">
|
<head>
|
<meta charset="UTF-8" />
|
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
|
<title>${escapeHtml(reportTitle)}</title>
|
<style>
|
:root {
|
color-scheme: light;
|
}
|
* {
|
box-sizing: border-box;
|
}
|
@page {
|
size: A4 ${orientation};
|
}
|
html,
|
body {
|
margin: 0;
|
padding: 0;
|
background: #ffffff;
|
color: #0f172a;
|
font-family: "Microsoft YaHei", "PingFang SC", "Helvetica Neue", Arial, sans-serif;
|
-webkit-print-color-adjust: exact;
|
print-color-adjust: exact;
|
}
|
body {
|
padding: 0;
|
}
|
.report-page {
|
width: 100%;
|
}
|
.report-title-wrap {
|
border-bottom: 1px solid #cbd5e1;
|
padding-bottom: 16px;
|
}
|
.report-title {
|
line-height: 1.2;
|
color: #0f172a;
|
}
|
.title-left {
|
text-align: left;
|
}
|
.title-center {
|
text-align: center;
|
}
|
.title-right {
|
text-align: right;
|
}
|
.title-normal {
|
font-size: 18px;
|
font-weight: 500;
|
}
|
.title-strong {
|
font-size: 22px;
|
font-weight: 600;
|
}
|
.title-prominent {
|
font-size: 26px;
|
font-weight: 700;
|
}
|
.report-meta {
|
display: grid;
|
grid-template-columns: repeat(4, minmax(0, 1fr));
|
gap: 10px;
|
margin-top: 12px;
|
font-size: 11px;
|
color: #475569;
|
}
|
.report-meta-item {
|
min-width: 0;
|
}
|
.report-meta-label {
|
color: #94a3b8;
|
}
|
.report-meta-value {
|
margin-left: 8px;
|
color: #334155;
|
word-break: break-word;
|
}
|
.report-table-wrap {
|
margin-top: 16px;
|
border: 1px solid #cbd5e1;
|
overflow: hidden;
|
}
|
.report-table-wrap-borderless {
|
border: 0;
|
}
|
table {
|
width: 100%;
|
border-collapse: collapse;
|
table-layout: auto;
|
font-size: 11px;
|
}
|
th,
|
td {
|
padding: 4px 6px;
|
vertical-align: top;
|
word-break: break-all;
|
}
|
.cell-bordered {
|
border: 1px solid #cbd5e1;
|
}
|
.cell-borderless {
|
border: 0;
|
}
|
th {
|
background: #f1f5f9;
|
color: #475569;
|
font-weight: 600;
|
}
|
td {
|
color: #334155;
|
}
|
.cell-left {
|
text-align: left;
|
}
|
.cell-center {
|
text-align: center;
|
}
|
.cell-right {
|
text-align: right;
|
}
|
.empty-cell {
|
padding: 32px 12px;
|
text-align: center;
|
color: #94a3b8;
|
}
|
@media print {
|
html,
|
body {
|
background: #ffffff;
|
}
|
body {
|
padding: 0;
|
}
|
}
|
</style>
|
</head>
|
<body>
|
<div class="report-page">
|
<div class="report-title-wrap">
|
<div class="report-title ${titleClass}">${escapeHtml(reportTitle)}</div>
|
</div>
|
<div class="report-meta">${metaHtml}</div>
|
<div class="${tableWrapClass}">
|
<table>
|
<thead>
|
<tr>${headerHtml}</tr>
|
</thead>
|
<tbody>${bodyHtml}</tbody>
|
</table>
|
</div>
|
</div>
|
<script>
|
window.addEventListener('load', () => {
|
window.focus();
|
setTimeout(() => {
|
window.print();
|
}, 50);
|
});
|
window.addEventListener('afterprint', () => {
|
window.close();
|
});
|
</script>
|
</body>
|
</html>`
|
}
|
|
export function printReportDocument(payload = {}) {
|
if (typeof window === 'undefined') {
|
return
|
}
|
|
const printWindow = window.open('', '_blank')
|
if (!printWindow) {
|
return
|
}
|
|
printWindow.document.open()
|
printWindow.document.write(buildPrintDocumentHtml(payload))
|
printWindow.document.close()
|
}
|