fix: "export as .pdf" broken
This commit is contained in:
@ -4,12 +4,15 @@
|
|||||||
writeFinalReport,
|
writeFinalReport,
|
||||||
type WriteFinalReportParams,
|
type WriteFinalReportParams,
|
||||||
} from '~/lib/deep-research'
|
} from '~/lib/deep-research'
|
||||||
|
import jsPDF from 'jspdf'
|
||||||
|
|
||||||
interface CustomReportParams extends WriteFinalReportParams {
|
interface CustomReportParams extends WriteFinalReportParams {
|
||||||
visitedUrls: string[]
|
visitedUrls: string[]
|
||||||
}
|
}
|
||||||
|
|
||||||
const { t } = useI18n()
|
const { t, locale } = useI18n()
|
||||||
|
const toast = useToast()
|
||||||
|
|
||||||
const error = ref('')
|
const error = ref('')
|
||||||
const loading = ref(false)
|
const loading = ref(false)
|
||||||
const loadingExportPdf = ref(false)
|
const loadingExportPdf = ref(false)
|
||||||
@ -20,6 +23,7 @@
|
|||||||
const isExportButtonDisabled = computed(
|
const isExportButtonDisabled = computed(
|
||||||
() => !reportContent.value || loading.value || loadingExportPdf.value,
|
() => !reportContent.value || loading.value || loadingExportPdf.value,
|
||||||
)
|
)
|
||||||
|
let pdf: jsPDF | undefined
|
||||||
|
|
||||||
async function generateReport(params: CustomReportParams) {
|
async function generateReport(params: CustomReportParams) {
|
||||||
loading.value = true
|
loading.value = true
|
||||||
@ -44,49 +48,88 @@
|
|||||||
const element = document.getElementById('report-content')
|
const element = document.getElementById('report-content')
|
||||||
if (!element) return
|
if (!element) return
|
||||||
|
|
||||||
// Create a temp container
|
|
||||||
const tempContainer = document.createElement('div')
|
|
||||||
loadingExportPdf.value = true
|
loadingExportPdf.value = true
|
||||||
|
|
||||||
try {
|
try {
|
||||||
// Dinamically import html2pdf
|
// 创建 PDF 实例
|
||||||
// @ts-ignore
|
if (!pdf) {
|
||||||
const html2pdf = (await import('html2pdf.js')).default
|
pdf = new jsPDF({
|
||||||
|
orientation: 'portrait',
|
||||||
tempContainer.innerHTML = element.innerHTML
|
|
||||||
tempContainer.className = element.className
|
|
||||||
|
|
||||||
// Use print-friendly styles
|
|
||||||
tempContainer.style.cssText = `
|
|
||||||
font-family: Arial, sans-serif;
|
|
||||||
color: black;
|
|
||||||
background-color: white;
|
|
||||||
padding: 20px;
|
|
||||||
`
|
|
||||||
|
|
||||||
document.body.appendChild(tempContainer)
|
|
||||||
|
|
||||||
const opt = {
|
|
||||||
margin: [10, 10],
|
|
||||||
filename: 'research-report.pdf',
|
|
||||||
image: { type: 'jpeg', quality: 0.98 },
|
|
||||||
html2canvas: {
|
|
||||||
scale: 2,
|
|
||||||
useCORS: true,
|
|
||||||
backgroundColor: '#ffffff',
|
|
||||||
},
|
|
||||||
jsPDF: {
|
|
||||||
unit: 'mm',
|
unit: 'mm',
|
||||||
format: 'a4',
|
format: 'a4',
|
||||||
orientation: 'portrait',
|
})
|
||||||
},
|
|
||||||
}
|
}
|
||||||
|
|
||||||
await html2pdf().set(opt).from(tempContainer).save()
|
// Load Chinese font
|
||||||
|
if (locale.value === 'zh') {
|
||||||
|
try {
|
||||||
|
if (!pdf.getFontList().SourceHanSans?.length) {
|
||||||
|
toast.add({
|
||||||
|
title: t('researchReport.downloadingFonts'),
|
||||||
|
duration: 5000,
|
||||||
|
color: 'info',
|
||||||
|
})
|
||||||
|
const fontUrl = '/fonts/SourceHanSansCN-VF.ttf'
|
||||||
|
pdf.addFont(fontUrl, 'SourceHanSans', 'normal')
|
||||||
|
pdf.setFont('SourceHanSans')
|
||||||
|
}
|
||||||
|
} catch (e: any) {
|
||||||
|
toast.add({
|
||||||
|
title: t('researchReport.downloadFontFailed'),
|
||||||
|
description: e.message,
|
||||||
|
duration: 8000,
|
||||||
|
color: 'error',
|
||||||
|
})
|
||||||
|
console.warn(
|
||||||
|
'Failed to load Chinese font, fallback to default font:',
|
||||||
|
e,
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// 设置字体大小和行高
|
||||||
|
const fontSize = 10.5
|
||||||
|
const lineHeight = 1.5
|
||||||
|
pdf.setFontSize(fontSize)
|
||||||
|
|
||||||
|
// 设置页面边距(单位:mm)
|
||||||
|
const margin = {
|
||||||
|
top: 20,
|
||||||
|
right: 20,
|
||||||
|
bottom: 20,
|
||||||
|
left: 20,
|
||||||
|
}
|
||||||
|
|
||||||
|
// 获取纯文本内容
|
||||||
|
const content = element.innerText
|
||||||
|
|
||||||
|
// 计算可用宽度(mm)
|
||||||
|
const pageWidth = pdf.internal.pageSize.getWidth()
|
||||||
|
const maxWidth = pageWidth - margin.left - margin.right
|
||||||
|
|
||||||
|
// 分割文本为行
|
||||||
|
const lines = pdf.splitTextToSize(content, maxWidth)
|
||||||
|
|
||||||
|
// 计算当前位置
|
||||||
|
let y = margin.top
|
||||||
|
|
||||||
|
// 逐行添加文本
|
||||||
|
for (const line of lines) {
|
||||||
|
// 检查是否需要新页
|
||||||
|
if (y > pdf.internal.pageSize.getHeight() - margin.bottom) {
|
||||||
|
pdf.addPage()
|
||||||
|
y = margin.top
|
||||||
|
}
|
||||||
|
|
||||||
|
// 添加文本
|
||||||
|
pdf.text(line, margin.left, y)
|
||||||
|
y += fontSize * lineHeight
|
||||||
|
}
|
||||||
|
|
||||||
|
pdf.save('research-report.pdf')
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
console.error('Export to PDF failed:', error)
|
console.error('Export to PDF failed:', error)
|
||||||
} finally {
|
} finally {
|
||||||
document.body.removeChild(tempContainer)
|
|
||||||
loadingExportPdf.value = false
|
loadingExportPdf.value = false
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -69,6 +69,8 @@
|
|||||||
"sources": "Sources",
|
"sources": "Sources",
|
||||||
"waiting": "Waiting for report...",
|
"waiting": "Waiting for report...",
|
||||||
"generating": "Generating report...",
|
"generating": "Generating report...",
|
||||||
"error": "Generate report failed: {0}"
|
"error": "Generate report failed: {0}",
|
||||||
|
"downloadingFonts": "Downloading necessary fonts, this may take some time...",
|
||||||
|
"downloadFontFailed": "Download font failed"
|
||||||
}
|
}
|
||||||
}
|
}
|
@ -69,6 +69,8 @@
|
|||||||
"sources": "来源",
|
"sources": "来源",
|
||||||
"waiting": "等待报告...",
|
"waiting": "等待报告...",
|
||||||
"generating": "生成报告中...",
|
"generating": "生成报告中...",
|
||||||
"error": "生成报告失败:{0}"
|
"error": "生成报告失败:{0}",
|
||||||
|
"downloadingFonts": "正在下载必要字体,可能需要较长时间...",
|
||||||
|
"downloadFontFailed": "下载字体失败"
|
||||||
}
|
}
|
||||||
}
|
}
|
@ -268,7 +268,7 @@ export async function deepResearch({
|
|||||||
})
|
})
|
||||||
try {
|
try {
|
||||||
const result = await useTavily().search(searchQuery.query, {
|
const result = await useTavily().search(searchQuery.query, {
|
||||||
maxResults: 5,
|
maxResults: 1,
|
||||||
})
|
})
|
||||||
console.log(
|
console.log(
|
||||||
`Ran ${searchQuery.query}, found ${result.results.length} contents`,
|
`Ran ${searchQuery.query}, found ${result.results.length} contents`,
|
||||||
|
@ -21,8 +21,8 @@
|
|||||||
"@tailwindcss/typography": "^0.5.16",
|
"@tailwindcss/typography": "^0.5.16",
|
||||||
"@tavily/core": "^0.0.3",
|
"@tavily/core": "^0.0.3",
|
||||||
"ai": "^4.1.28",
|
"ai": "^4.1.28",
|
||||||
"html2pdf.js": "^0.9.3",
|
|
||||||
"js-tiktoken": "^1.0.18",
|
"js-tiktoken": "^1.0.18",
|
||||||
|
"jspdf": "^2.5.2",
|
||||||
"marked": "^15.0.7",
|
"marked": "^15.0.7",
|
||||||
"nuxt": "^3.15.4",
|
"nuxt": "^3.15.4",
|
||||||
"p-limit": "^6.2.0",
|
"p-limit": "^6.2.0",
|
||||||
|
582
pnpm-lock.yaml
generated
582
pnpm-lock.yaml
generated
File diff suppressed because it is too large
Load Diff
BIN
public/fonts/SourceHanSansCN-VF.ttf
Normal file
BIN
public/fonts/SourceHanSansCN-VF.ttf
Normal file
Binary file not shown.
Reference in New Issue
Block a user