169 lines
5.7 KiB
TypeScript
169 lines
5.7 KiB
TypeScript
|
import jsPDF from 'jspdf'
|
|||
|
import html2canvas from 'html2canvas'
|
|||
|
|
|||
|
// PDF生成器类
|
|||
|
export class PDFGenerator {
|
|||
|
// 生成制度PDF
|
|||
|
static async generateRegulationPDF(regulation: any): Promise<Blob> {
|
|||
|
// 创建临时HTML元素
|
|||
|
const tempDiv = document.createElement('div')
|
|||
|
tempDiv.style.position = 'absolute'
|
|||
|
tempDiv.style.left = '-9999px'
|
|||
|
tempDiv.style.top = '-9999px'
|
|||
|
tempDiv.style.width = '800px'
|
|||
|
tempDiv.style.padding = '40px'
|
|||
|
tempDiv.style.backgroundColor = 'white'
|
|||
|
tempDiv.style.fontFamily = 'Arial, sans-serif'
|
|||
|
tempDiv.style.fontSize = '14px'
|
|||
|
tempDiv.style.lineHeight = '1.6'
|
|||
|
tempDiv.style.color = '#333'
|
|||
|
|
|||
|
// 添加水印样式
|
|||
|
tempDiv.style.position = 'relative'
|
|||
|
tempDiv.style.overflow = 'hidden'
|
|||
|
|
|||
|
// 生成HTML内容
|
|||
|
tempDiv.innerHTML = `
|
|||
|
<div style="position: relative; z-index: 1;">
|
|||
|
<!-- 水印 -->
|
|||
|
<div style="
|
|||
|
position: absolute;
|
|||
|
top: 50%;
|
|||
|
left: 50%;
|
|||
|
transform: translate(-50%, -50%) rotate(-45deg);
|
|||
|
font-size: 48px;
|
|||
|
color: rgba(200, 200, 200, 0.3);
|
|||
|
font-weight: bold;
|
|||
|
z-index: 0;
|
|||
|
pointer-events: none;
|
|||
|
white-space: nowrap;
|
|||
|
">制度管理系统</div>
|
|||
|
|
|||
|
<!-- 标题 -->
|
|||
|
<h1 style="
|
|||
|
text-align: center;
|
|||
|
font-size: 24px;
|
|||
|
font-weight: bold;
|
|||
|
margin-bottom: 30px;
|
|||
|
color: #333;
|
|||
|
">${regulation.title || '制度文档'}</h1>
|
|||
|
|
|||
|
<!-- 基本信息 -->
|
|||
|
<div style="margin-bottom: 30px;">
|
|||
|
<table style="width: 100%; border-collapse: collapse;">
|
|||
|
<tr>
|
|||
|
<td style="padding: 8px 0; border-bottom: 1px solid #eee;"><strong>制度类型:</strong>${regulation.regulationType || '-'}</td>
|
|||
|
<td style="padding: 8px 0; border-bottom: 1px solid #eee;"><strong>发布人:</strong>${regulation.createBy || '-'}</td>
|
|||
|
</tr>
|
|||
|
<tr>
|
|||
|
<td style="padding: 8px 0; border-bottom: 1px solid #eee;"><strong>发布时间:</strong>${regulation.publishTime || '-'}</td>
|
|||
|
<td style="padding: 8px 0; border-bottom: 1px solid #eee;"><strong>生效日期:</strong>${regulation.effectiveTime || '-'}</td>
|
|||
|
</tr>
|
|||
|
<tr>
|
|||
|
<td style="padding: 8px 0; border-bottom: 1px solid #eee;"><strong>适用范围:</strong>${regulation.scope || '-'}</td>
|
|||
|
<td style="padding: 8px 0; border-bottom: 1px solid #eee;"><strong>制度级别:</strong>${regulation.level || '-'}</td>
|
|||
|
</tr>
|
|||
|
<tr>
|
|||
|
<td style="padding: 8px 0; border-bottom: 1px solid #eee;"><strong>版本:</strong>${regulation.version || '1.0'}</td>
|
|||
|
<td style="padding: 8px 0; border-bottom: 1px solid #eee;"></td>
|
|||
|
</tr>
|
|||
|
</table>
|
|||
|
</div>
|
|||
|
|
|||
|
<!-- 分隔线 -->
|
|||
|
<hr style="border: none; border-top: 2px solid #ddd; margin: 30px 0;">
|
|||
|
|
|||
|
<!-- 制度内容 -->
|
|||
|
<div style="margin-bottom: 30px;">
|
|||
|
<h2 style="font-size: 18px; font-weight: bold; margin-bottom: 15px; color: #333;">制度内容:</h2>
|
|||
|
<div style="
|
|||
|
white-space: pre-wrap;
|
|||
|
word-wrap: break-word;
|
|||
|
line-height: 1.8;
|
|||
|
text-align: justify;
|
|||
|
">${regulation.content || ''}</div>
|
|||
|
</div>
|
|||
|
|
|||
|
${regulation.remark ? `
|
|||
|
<!-- 备注信息 -->
|
|||
|
<div style="margin-bottom: 30px;">
|
|||
|
<h2 style="font-size: 18px; font-weight: bold; margin-bottom: 15px; color: #333;">备注:</h2>
|
|||
|
<div style="
|
|||
|
white-space: pre-wrap;
|
|||
|
word-wrap: break-word;
|
|||
|
line-height: 1.8;
|
|||
|
text-align: justify;
|
|||
|
">${regulation.remark}</div>
|
|||
|
</div>
|
|||
|
` : ''}
|
|||
|
|
|||
|
<!-- 页脚 -->
|
|||
|
<div style="
|
|||
|
margin-top: 50px;
|
|||
|
padding-top: 20px;
|
|||
|
border-top: 1px solid #ddd;
|
|||
|
text-align: center;
|
|||
|
font-size: 12px;
|
|||
|
color: #666;
|
|||
|
">
|
|||
|
生成时间:${new Date().toLocaleString('zh-CN')} | 制度ID:${regulation.regulationId || '-'}
|
|||
|
</div>
|
|||
|
</div>
|
|||
|
`
|
|||
|
|
|||
|
// 添加到DOM
|
|||
|
document.body.appendChild(tempDiv)
|
|||
|
|
|||
|
try {
|
|||
|
// 使用html2canvas转换为图片
|
|||
|
const canvas = await html2canvas(tempDiv, {
|
|||
|
scale: 2, // 提高清晰度
|
|||
|
useCORS: true,
|
|||
|
allowTaint: true,
|
|||
|
backgroundColor: '#ffffff',
|
|||
|
width: 800,
|
|||
|
height: tempDiv.scrollHeight
|
|||
|
})
|
|||
|
|
|||
|
// 创建PDF
|
|||
|
const imgData = canvas.toDataURL('image/png')
|
|||
|
const pdf = new jsPDF('p', 'mm', 'a4')
|
|||
|
|
|||
|
const imgWidth = 210 // A4宽度
|
|||
|
const pageHeight = 295 // A4高度
|
|||
|
const imgHeight = (canvas.height * imgWidth) / canvas.width
|
|||
|
let heightLeft = imgHeight
|
|||
|
let position = 0
|
|||
|
|
|||
|
// 添加第一页
|
|||
|
pdf.addImage(imgData, 'PNG', 0, position, imgWidth, imgHeight)
|
|||
|
heightLeft -= pageHeight
|
|||
|
|
|||
|
// 添加后续页面
|
|||
|
while (heightLeft >= 0) {
|
|||
|
position = heightLeft - imgHeight
|
|||
|
pdf.addPage()
|
|||
|
pdf.addImage(imgData, 'PNG', 0, position, imgWidth, imgHeight)
|
|||
|
heightLeft -= pageHeight
|
|||
|
}
|
|||
|
|
|||
|
// 返回PDF blob
|
|||
|
return pdf.output('blob')
|
|||
|
} finally {
|
|||
|
// 清理临时元素
|
|||
|
document.body.removeChild(tempDiv)
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
// 下载PDF文件
|
|||
|
static downloadPDF(blob: Blob, filename: string) {
|
|||
|
const url = URL.createObjectURL(blob)
|
|||
|
const link = document.createElement('a')
|
|||
|
link.href = url
|
|||
|
link.download = filename
|
|||
|
document.body.appendChild(link)
|
|||
|
link.click()
|
|||
|
document.body.removeChild(link)
|
|||
|
URL.revokeObjectURL(url)
|
|||
|
}
|
|||
|
}
|