import * as crypto from 'crypto' import { Injectable, Logger } from '@nestjs/common' @Injectable() export class ResumePdfService { private readonly logger = new Logger(ResumePdfService.name) async generatePdf(params: { title: string content: string targetPosition?: string userName?: string }): Promise { const { default: puppeteer } = await import('puppeteer') const html = this.buildHtml(params) const browser = await puppeteer.launch({ executablePath: '/root/.cache/puppeteer/chrome/linux-149.0.7827.22/chrome-linux64/chrome', args: ['--no-sandbox', '--disable-setuid-sandbox', '--disable-dev-shm-usage'], }) try { const page = await browser.newPage() await page.setContent(html, { waitUntil: 'load' }) const pdf = await page.pdf({ format: 'A4', printBackground: true, margin: { top: '20mm', bottom: '20mm', left: '15mm', right: '15mm' }, }) return Buffer.from(pdf) } finally { await browser.close() } } private escapeHtml(str: string): string { return str.replace(/&/g, '&').replace(//g, '>') .replace(/"/g, '"').replace(/'/g, ''') } private buildHtml(params: { title: string content: string targetPosition?: string userName?: string }): string { const contentHtml = this.escapeHtml(params.content) .replace(/\n/g, '
') .replace(/### (.+)/g, '

$1

') .replace(/\*\*(.+?)\*\*/g, '$1') return `

${this.escapeHtml(params.title)}

${params.targetPosition ? `目标岗位: ${this.escapeHtml(params.targetPosition)}` : ''}
${contentHtml}
` } computeHash(content: string): string { return crypto.createHash('md5').update(content).digest('hex') } }