spa/.claude/skills/softcopyright/scripts/html-to-pdf.js

205 lines
5.6 KiB
JavaScript
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

/**
* HTML自动转换为PDF
* 使用Puppeteer将HTML转换为高质量PDF
*/
const puppeteer = require('puppeteer');
const fs = require('fs-extra');
const path = require('path');
const chalk = require('chalk');
/**
* 将HTML文件转换为PDF
* @param {string} htmlPath HTML文件路径
* @param {string} outputPath PDF输出路径
* @returns {Promise<string>} PDF文件路径
*/
async function convertHTMLToPDF(htmlPath, outputPath) {
let browser;
try {
console.log(chalk.yellow('🔄 正在将HTML转换为PDF...'));
// 启动Puppeteer浏览器
browser = await puppeteer.launch({
headless: true,
args: [
'--no-sandbox',
'--disable-setuid-sandbox',
'--disable-dev-shm-usage',
'--disable-gpu',
'--lang=zh-CN,zh,zh-TW,en-US,en',
'--disable-extensions',
'--disable-plugins',
'--disable-default-apps'
]
});
const page = await browser.newPage();
// 设置视口
await page.setViewport({ width: 1200, height: 800 });
// 设置用户代理
await page.setUserAgent('Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/120.0.0.0 Safari/537.36');
// 加载HTML文件
await page.goto(`file://${htmlPath}`, {
waitUntil: ['networkidle0', 'domcontentloaded'],
timeout: 30000
});
// 等待页面完全加载
await page.waitForTimeout(2000);
// 检查页面是否正确加载
const title = await page.title();
console.log(chalk.cyan(`📄 页面标题: ${title}`));
// 生成PDF
await page.pdf({
path: outputPath,
format: 'A4',
printBackground: true,
margin: {
top: '20mm',
right: '15mm',
bottom: '20mm',
left: '15mm'
},
displayHeaderFooter: true,
headerTemplate: `
<div style="font-size:10px; text-align:center; width:100%; color:#666; font-family: Arial, 'PingFang SC', sans-serif;">
软件说明书 - ${path.basename(htmlPath, '.html')}
</div>
`,
footerTemplate: `
<div style="font-size:10px; text-align:center; width:100%; color:#666; font-family: Arial, 'PingFang SC', sans-serif;">
<span class="pageNumber"></span> / <span class="totalPages"></span>
</div>
`,
preferCSSPageSize: true,
scale: 1.0
});
console.log(chalk.green(`✅ PDF生成成功: ${outputPath}`));
return outputPath;
} catch (error) {
console.error(chalk.red('❌ PDF转换失败:'), error.message);
throw error;
} finally {
if (browser) {
await browser.close();
}
}
}
/**
* 自动转换HTML为PDF的便捷函数
* @param {Object} projectInfo 项目信息
* @param {string} outputDir 输出目录
* @returns {Promise<string>} PDF文件路径
*/
async function generateManualPDF(projectInfo, outputDir) {
const moment = require('moment');
try {
console.log(chalk.yellow('📝 生成HTML并转换为PDF...'));
const timestamp = moment().format('YYYYMMDD_HHMMSS');
// 首先生成HTML
const { generateManualHTML } = require('./simple-doc-generator');
const htmlPath = await generateManualHTML(projectInfo, outputDir);
// 生成PDF文件名
const pdfFileName = `软件说明书_${projectInfo.name}_${timestamp}.pdf`;
const pdfPath = path.join(outputDir, pdfFileName);
// 转换为PDF
await convertHTMLToPDF(htmlPath, pdfPath);
// 删除临时HTML文件可选
// await fs.remove(htmlPath);
console.log(chalk.green(`🎉 完整流程完成!`));
console.log(chalk.blue(`📄 PDF文件: ${pdfPath}`));
console.log(chalk.gray(`🌐 HTML文件: ${htmlPath}`));
return pdfPath;
} catch (error) {
throw new Error(`自动PDF生成失败: ${error.message}`);
}
}
/**
* 批量转换HTML文件为PDF
* @param {string} inputDir 输入目录
* @param {string} outputDir 输出目录
* @returns {Promise<string[]>} 生成的PDF文件路径列表
*/
async function batchConvertHTMLToPDF(inputDir, outputDir) {
try {
console.log(chalk.yellow('🔄 批量转换HTML为PDF...'));
// 确保输出目录存在
await fs.ensureDir(outputDir);
// 查找所有HTML文件
const htmlFiles = await fs.readdir(inputDir);
const htmlFileList = htmlFiles.filter(file => file.endsWith('.html'));
if (htmlFileList.length === 0) {
console.log(chalk.yellow('⚠️ 未找到HTML文件'));
return [];
}
const pdfFiles = [];
for (const htmlFile of htmlFileList) {
try {
const htmlPath = path.join(inputDir, htmlFile);
const pdfFile = htmlFile.replace('.html', '.pdf');
const pdfPath = path.join(outputDir, pdfFile);
console.log(chalk.cyan(`🔄 转换: ${htmlFile} -> ${pdfFile}`));
await convertHTMLToPDF(htmlPath, pdfPath);
pdfFiles.push(pdfPath);
} catch (error) {
console.error(chalk.red(`❌ 转换失败 ${htmlFile}:`), error.message);
}
}
console.log(chalk.green(`✅ 批量转换完成,生成 ${pdfFiles.length} 个PDF文件`));
return pdfFiles;
} catch (error) {
throw new Error(`批量转换失败: ${error.message}`);
}
}
/**
* 检查Puppeteer是否可用
* @returns {Promise<boolean>}
*/
async function checkPuppeteerAvailability() {
try {
await puppeteer.createBrowserFetcher().download('chrome');
return true;
} catch (error) {
console.warn(chalk.yellow('⚠️ Puppeteer检查失败:'), error.message);
return false;
}
}
module.exports = {
convertHTMLToPDF,
generateManualPDF,
batchConvertHTMLToPDF,
checkPuppeteerAvailability
};