const fs = require('fs') const path = require('path') const compressing = require('compressing') const rimrif = require('rimraf') const shell = require('shelljs'); const crypto = require('crypto'); const { LibreOffice } = require("chromiumly"); const tempDir = path.join(__dirname , "temp") const OSS = require("ali-oss"); const ALI_OSS_BUCKET = process.env.ALI_OSS_BUCKET || "hep-textbook" const ALI_OSS_ACCESS_KEY_ID = process.env.ALI_OSS_ACCESS_KEY_ID || "LTAI5t6AbTiAvXmeoVdJZhL3" const ALI_OSS_ACCESS_KEY_SECRET = process.env.ALI_OSS_ACCESS_KEY_SECRET || "KLtQRdIW69KLP7jnzHNUf7eKmdptxH" export async function uploadFileToOSS(filePath){ let client = new OSS({ // yourRegion填写Bucket所在地域。以华东1(杭州)为例,yourRegion填写为oss-cn-hangzhou。 region: "oss-cn-beijing", accessKeyId: ALI_OSS_ACCESS_KEY_ID, accessKeySecret: ALI_OSS_ACCESS_KEY_SECRET, // 填写Bucket名称。 bucket: ALI_OSS_BUCKET || "hep-textbook", }); let now = new Date(); let fileName = getFileName(filePath); let fileKey = `export/report/${fileName}`; const r1 = await client?.put(fileKey, filePath); console.log('put success: %j', r1); return r1 } export function getFileName(filePath) { // 使用 '/' 或 '\' 作为分隔符,分割路径 const parts = filePath.split(/[/\\]/); // 返回最后一个部分,即文件名 return parts.pop(); } module.exports.uploadFileToOSS = uploadFileToOSS /** * 将给定的文件路径数组打包成指定名称的zip压缩包 * @param {Array} filePathList - 要打包的文件路径数组 * @param {string} outputZipName - 输出的zip文件名称 */ export function createZip(filePathList, outputZipName) { let zipStream = new compressing.zip.Stream(); return new Promise((resolve)=>{ try { let outputPath = path.join(tempDir,outputZipName) // 遍历文件路径列表,将每个文件添加到zip流中 for (const filePath of filePathList) { // 检查文件是否存在 if (fs.existsSync(filePath)) { // 将文件添加到zip流中 zipStream.addEntry(filePath); } else { console.error(`文件不存在: ${filePath}`); } } // 创建一个写入流 const output = fs.createWriteStream(outputPath); // 使用 compressing 库的 zip 方法将文件打包 console.log(filePathList) // await compressing.zip.compressDir(filePathList, output); // 将zip流写入文件 zipStream.pipe(output); output.on('finish', () => { console.log(`成功创建压缩包: ${outputPath}`); resolve(outputPath) }); output.on('error', (error) => { console.error('写入压缩包时出错:', error); resolve(null) }); // console.log(`成功创建压缩包: ${outputPath}`); // return outputPath } catch (error) { console.error('创建压缩包时出错:', error); return null } }) } module.exports.createZip = createZip /** * 将 DOCX 文件转换为 PDF * * @param {string} docxPath - 要转换的 DOCX 文件的路径 * @param {string} outputPath - 输出 PDF 文件的路径 * @returns {Promise} */ export async function docsToPdf(docxPath, outputPath) { try { const files = [docxPath]; const pdfBuffer = await LibreOffice.convert({ files, properties: { // 你可以在这里设置页面属性 }, pdfa: false, // PDF/A 选项 pdfUA: false, // PDF/UA 选项 merge: false, // 是否合并PDF metadata: { // 你可以在这里添加元数据 }, // losslessImageCompression: false, // reduceImageResolution: false, // quality: 90, // JPG 导出质量 // maxImageResolution: 300 // 最大图像分辨率 }); // 将 Buffer 写入输出文件 fs.writeFileSync(outputPath, pdfBuffer); console.log(`成功将 {outputPath}`); } catch (error) { console.error('转换失败:', error); } } module.exports.docsToPdf = docsToPdf /** * docx 替换模板字符串内容 * @example // 要替换内容的模板 let inputDocx = 'cs.docx' // 替换完成的docx文件 let outputDocx = 'dd.docx' // {{xx}} 处要替换的内容 let replaceData = { name: '替换name处的内容', age: '替换age处的内容', } replaceDocx(inputDocx, outputDocx, replaceData) */ export function replaceDocx(inputDocxPath, outputDocxPath, options,eventMap) { return new Promise((resolve,reject)=>{ // 解压出来的临时目录 let md5 = crypto.createHash('md5'); let outmd5 = md5.update(outputDocxPath).digest('hex') let tempDocxPath = path.join(tempDir , outmd5) // 要替换的xml文件位置 let tempDocxXMLName = path.join(tempDocxPath,`word/document.xml`) // 压缩文件夹为文件 let dir_to_docx = (inputFilePath, outputFilePath) => { outputFilePath = path.join(tempDir,outputFilePath) // 创建压缩流 let zipStream = new compressing.zip.Stream() // 写出流 let outStream = fs.createWriteStream(outputFilePath) fs.readdir(inputFilePath, null, (err, files) => { if (!err) { files.map(file => path.join(inputFilePath, file)) .forEach(file => { zipStream.addEntry(file) }) } }) // 写入文件内容 zipStream.pipe(outStream) .on('close', () => { // 打包完成后删除临时目录 // console.log(tempDocxPath) eventMap["onDocxComplete"]&&eventMap["onDocxComplete"](outputFilePath) shell.rm("-r",tempDocxPath) // rimrif.rimrafSync(tempDocxPath) resolve(true) }) } // 替换word/document.xml文件中{{xx}}处的内容 let replaceXML = (data, text) => { Object.keys(data).forEach(key => { text = text.replaceAll(`{{${key}}}`, data[key]) }) return text } // 解压docx文件替换内容重新打包成docx文件 compressing.zip.uncompress(inputDocxPath, tempDocxPath) .then(() => { // 读写要替换内容的xml文件 fs.readFile(tempDocxXMLName, null, (err, data) => { if (!err) { let text = data.toString() text = replaceXML(options, text) fs.writeFile(tempDocxXMLName, text, (err) => { if (!err) { dir_to_docx(tempDocxPath, outputDocxPath) } else { reject(err) } }) } else { reject(err) } }) }).catch(err => { reject(err) }) }) } module.exports.replaceDocx = replaceDocx