| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150 |
- // composables/usePDF.js
- import { ref } from 'vue'
- import html2pdf from 'html2pdf.js'
- import { PDFDocument, rgb } from 'pdf-lib'
- import fontkit from '@pdf-lib/fontkit' // 关键:导入适配版fontkit
- export function usePDF() {
- const loading = ref(false)
- const error = ref(null)
- // 基础HTML转PDF(单页)
- const generateSinglePDF = async (element, options = {}) => {
- const defaultOptions = {
- margin: [10, 10, 10, 10],
- image: { type: 'jpeg', quality: 0.98 },
- html2canvas: {
- scale: 2,
- letterRendering: true,
- useCORS: true
- },
- jsPDF: {
- unit: 'mm',
- format: 'a4',
- orientation: 'portrait'
- },
- filename: 'temp.pdf',
- save: false
- }
- const mergedOptions = { ...defaultOptions, ...options }
- const pdfBlob = await html2pdf().set(mergedOptions).from(element).output('blob')
- return pdfBlob
- }
- // 加载中文字体(修复fontkit注册问题)
- const loadChineseFont = async (pdfDoc) => {
- // 1. 注册fontkit到PDFDocument(核心修复)
- pdfDoc.registerFontkit(fontkit)
- // 2. 加载中文字体文件(思源黑体,确保路径正确)
- const fontUrl = '/SourceHanSansSC-Regular.otf'
- // try {
- const fontResponse = await fetch(fontUrl)
- if (!fontResponse.ok) throw new Error('字体文件加载失败')
- const fontArrayBuffer = await fontResponse.arrayBuffer()
-
- // 3. 嵌入中文字体
- const font = await pdfDoc.embedFont(fontArrayBuffer)
- return font
- // } catch (err) {
- // console.error('字体加载失败:', err)
- // throw new Error('中文字体加载失败,请检查字体文件路径')
- // }
- }
- // 物理分页生成PDF(最终完整版)
- const generateWithPagination = async (pageElements, options = {}) => {
- loading.value = true
- error.value = null
- try {
- const { filename = '中文分页文档.pdf' } = options
-
- // 1. 创建PDF文档实例
- const finalPdfDoc = await PDFDocument.create()
- // 2. 加载中文字体
- const chineseFont = await loadChineseFont(finalPdfDoc)
- // 3. 遍历所有分页节点,逐个生成并合并页面
- for (let i = 0; i < pageElements.length; i++) {
- const element = pageElements[i]
- if (!element) continue // 跳过空节点
- // 生成当前页的PDF Blob
- const pageBlob = await generateSinglePDF(element, options)
- const pageArrayBuffer = await new Response(pageBlob).arrayBuffer()
-
- // 加载临时PDF并复制页面
- const pagePdfDoc = await PDFDocument.load(pageArrayBuffer)
- const [copiedPage] = await finalPdfDoc.copyPages(pagePdfDoc, [0])
- // 绘制中文页码(支持中文渲染)
- const { width, height } = copiedPage.getSize()
- copiedPage.drawText(`第 ${i + 1} 页 / 共 ${pageElements.length} 页`, {
- x: width / 2 - 60, // 微调位置适配中文字符
- y: 12, // 页码在页面底部
- size: 12, // 字体大小
- font: chineseFont, // 使用嵌入的中文字体
- color: rgb(0.3, 0.3, 0.3) // 灰色页码
- })
- // 添加到最终PDF(物理分页核心)
- finalPdfDoc.addPage(copiedPage)
- }
- // 4. 生成并下载PDF
- const finalPdfBytes = await finalPdfDoc.save()
- const finalPdfBlob = new Blob([finalPdfBytes], { type: 'application/pdf' })
-
- // 原生下载(无需file-saver)
- const downloadLink = document.createElement('a')
- downloadLink.href = URL.createObjectURL(finalPdfBlob)
- downloadLink.download = filename
- downloadLink.click()
- URL.revokeObjectURL(downloadLink.href)
- return true
- } catch (err) {
- error.value = `PDF生成失败:${err.message}`
- console.error('分页PDF生成错误:', err)
- return false
- } finally {
- loading.value = false
- }
- }
- // 原有HTML转PDF方法(保持兼容)
- const generateFromHTML = async (element, options = {}) => {
- loading.value = true
- error.value = null
- try {
- const defaultOptions = {
- margin: [10, 10, 10, 10],
- filename: 'document.pdf',
- image: { type: 'jpeg', quality: 0.98 },
- html2canvas: { scale: 2, letterRendering: true, useCORS: true },
- jsPDF: { unit: 'mm', format: 'a4', orientation: 'portrait' }
- }
- const mergedOptions = { ...defaultOptions, ...options }
- await html2pdf().set(mergedOptions).from(element).save()
- return true
- } catch (err) {
- error.value = err.message
- console.error('PDF生成失败:', err)
- return false
- } finally {
- loading.value = false
- }
- }
- return {
- loading,
- error,
- generateFromHTML,
- generateWithPagination // 物理分页核心方法
- }
- }
|