移动端页面缩放
This commit is contained in:
@@ -183,3 +183,103 @@ export async function loadResumeTemplateData(resumeId: string): Promise<ResumeTe
|
||||
certificates: r.certificates || [],
|
||||
}
|
||||
}
|
||||
|
||||
// ==================== 生成文件对象(不触发下载,用于上传到服务器) ====================
|
||||
|
||||
/**
|
||||
* 生成简历PDF的File对象(不触发浏览器下载)
|
||||
* @param element 简历DOM元素
|
||||
* @param fileName 文件名(不含扩展名)
|
||||
* @returns PDF格式的File对象
|
||||
*/
|
||||
export async function generateResumePdfFile(element: HTMLElement, fileName: string): Promise<File> {
|
||||
const options = {
|
||||
margin: [10, 10, 10, 10] as [number, number, number, number],
|
||||
filename: `${fileName}.pdf`,
|
||||
image: { type: 'jpeg' as const, quality: 0.98 },
|
||||
html2canvas: { scale: 2, useCORS: true, logging: false },
|
||||
jsPDF: { unit: 'mm', format: 'a4', orientation: 'portrait' as const },
|
||||
pagebreak: { mode: ['css', 'legacy'] },
|
||||
}
|
||||
// 使用 outputPdf('blob') 获取 Blob,不触发下载
|
||||
const blob: Blob = await html2pdf().set(options).from(element).outputPdf('blob')
|
||||
return new File([blob], `${fileName}.pdf`, { type: 'application/pdf' })
|
||||
}
|
||||
|
||||
/**
|
||||
* 生成简历Word的File对象(不触发浏览器下载)
|
||||
* @param element 简历DOM元素
|
||||
* @param fileName 文件名(不含扩展名)
|
||||
* @returns Word格式的File对象
|
||||
*/
|
||||
export function generateResumeWordFile(element: HTMLElement, fileName: string): File {
|
||||
// 复用与 exportResumeWord 相同的 Word HTML 组装逻辑
|
||||
const wordCss = `
|
||||
@page WordSection1 {
|
||||
size: 595.3pt 841.9pt;
|
||||
mso-page-orientation: portrait;
|
||||
mso-header-margin: 0pt;
|
||||
mso-footer-margin: 0pt;
|
||||
mso-paper-source: 0;
|
||||
margin-top: 72pt;
|
||||
margin-right: 54pt;
|
||||
margin-bottom: 72pt;
|
||||
margin-left: 54pt;
|
||||
}
|
||||
div.WordSection1 { page: WordSection1; }
|
||||
body { font-family: 'SimSun', 'Songti SC', serif; color: #000; line-height: 1.6; margin: 0; padding: 0; }
|
||||
.job-resume-template { width: 100%; background: #fff; box-sizing: border-box; }
|
||||
.resume-html { padding: 0; font-family: 'SimSun', 'Songti SC', serif; color: #000; line-height: 1.6; }
|
||||
.resume-html__name { font-size: 24pt; font-weight: 700; margin: 0 0 4.8pt 0; line-height: 1.3; }
|
||||
.resume-html__contact { font-size: 12pt; color: #000; margin-bottom: 3.6pt; line-height: 1.5; }
|
||||
.resume-html__contact-row { display: flex; align-items: center; gap: 0; }
|
||||
.resume-html__separator { margin: 0 4.8pt; color: #777; }
|
||||
.resume-html__section-title { font-size: 17.3pt; font-weight: 700; color: #000; margin-top: 20pt; margin-bottom: 10pt; line-height: 1.3; }
|
||||
.resume-html__divider { height: 1.5px; background: #000; margin-bottom: 9.6pt; }
|
||||
.resume-html__summary { font-size: 12pt; line-height: 1.7; margin-bottom: 4.8pt; }
|
||||
.resume-html__item { margin-bottom: 9.6pt; }
|
||||
.resume-html__item-header { display: flex; align-items: flex-start; justify-content: space-between; margin-bottom: 2pt; }
|
||||
.resume-html__item-main { font-size: 13.2pt; font-weight: 600; color: #000; line-height: 1.4; }
|
||||
.resume-html__item-right { display: flex; align-items: center; gap: 4.8pt; flex-shrink: 0; text-align: right; }
|
||||
.resume-html__item-location { font-size: 12pt; color: #000; }
|
||||
.resume-html__item-date { font-size: 12pt; color: #000; white-space: nowrap; }
|
||||
.resume-html__item-desc { font-size: 12pt; color: #000; line-height: 1.7; margin-top: 2pt; }
|
||||
.resume-html__desc-list { margin: 0; padding-left: 0; list-style: none; mso-list: none; }
|
||||
.resume-html__desc-list li { font-size: 12pt; line-height: 1.7; color: #000; list-style: none; mso-list: none; margin-left: 0; padding-left: 24pt; text-indent: 0; }
|
||||
.resume-html__skills { font-size: 12pt; line-height: 1.7; }
|
||||
.resume-html__skill-row { margin-bottom: 2.4pt; }
|
||||
.resume-html__skill-label { font-weight: 600; }
|
||||
.resume-html__diff-highlight { background-color: #D4EDDA; color: #155724; border-radius: 2px; padding: 0 1px; }
|
||||
`
|
||||
|
||||
const parts: string[] = []
|
||||
parts.push('<html xmlns:o="urn:schemas-microsoft-com:office:office"')
|
||||
parts.push(' xmlns:w="urn:schemas-microsoft-com:office:word"')
|
||||
parts.push(' xmlns="http://www.w3.org/TR/REC-html40">')
|
||||
parts.push('<head>')
|
||||
parts.push('<meta charset="utf-8">')
|
||||
parts.push('<meta name="ProgId" content="Word.Document">')
|
||||
parts.push('<meta name="Generator" content="Microsoft Word 15">')
|
||||
parts.push('<!--[if gte mso 9]><xml>')
|
||||
parts.push('<w:WordDocument>')
|
||||
parts.push('<w:View>Print</w:View>')
|
||||
parts.push('<w:Zoom>100</w:Zoom>')
|
||||
parts.push('</w:WordDocument>')
|
||||
parts.push('</xml><![endif]-->')
|
||||
parts.push('<style>' + wordCss + '</style>')
|
||||
parts.push('</head>')
|
||||
parts.push('<body>')
|
||||
parts.push('<!--[if gte mso 9]><xml>')
|
||||
parts.push('<w:WordDocument>')
|
||||
parts.push('<w:BrowserLevel>MicrosoftInternetExplorer4</w:BrowserLevel>')
|
||||
parts.push('</w:WordDocument>')
|
||||
parts.push('</xml><![endif]-->')
|
||||
parts.push('<div class="WordSection1">' + element.outerHTML + '</div>')
|
||||
parts.push('</body>')
|
||||
parts.push('</html>')
|
||||
const fullHtml = parts.join('\n')
|
||||
|
||||
// 生成File对象,不触发下载
|
||||
const blob = new Blob([fullHtml], { type: 'application/msword' })
|
||||
return new File([blob], `${fileName}.doc`, { type: 'application/msword' })
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user