import { replaceDocx, docsToPdf, createZip, uploadFileToOSS } from "../../lib/docs"; // const Parse = global.Parse; const path = require("path") const TemplateDocxPath = path.join(__dirname,"template/模板-推荐申报表.docx") /** * 定义导出申报合集文档云函数 * @example * Cloud Code test curl -X POST -H "Content-Type: application/json" -H 'X-Parse-Application-Id: edu-textbook' -d '{ "processId": "Wz34loxdbO" }' http://127.0.0.1:61337/parse/functions/tbookExportReport curl -X POST -H "Content-Type: application/json" -H 'X-Parse-Application-Id: edu-textbook' -d '{ "processId": "Wz34loxdbO" }' http://8.140.98.43/parse/functions/tbookExportReport */ export function defineTbookExportReport(){ Parse.Cloud.define("tbookExportReport", async (request) => { let processId = request.params.processId; if(processId) { try{ let result = await exportProcessReportDocs(processId) if(result?.docsList?.length==0){ throw new Parse.Error(404,"合集内无申报教材") } return result }catch(err){ console.error(err) throw new Parse.Error(404,"导出申报合集失败") } } throw new Parse.Error(404,"未找到该流程合集") },{ fields : { processId:{ required:true } } }); } /** * 导出流程教材申报文件 * @returns * docsList * zipUrl */ async function exportProcessReportDocs(processId) { if(!processId) return {} let query = new Parse.Query("EduTextbook") query.equalTo("eduProcess",processId); let textbookList = await query.find(); let docsList = [] for (let index = 0; index < textbookList.length; index++) { let textbook = textbookList[index]; let result = await renderReportDocsByTextbook(textbook); docsList.push(result) } let zipPath,zipUrl if(docsList?.length){ zipPath = await createZip(docsList?.map(item=>item?.filePath),`流程合集-${processId}.zip`) if(zipPath){ zipUrl = (await uploadFileToOSS(zipPath))?.url || null } docsList = docsList.map(item=>{return {code:item.code,title:item.title,url:item?.url}}) } console.log(textbookList); console.log(docsList) console.log(processId) let result = { docsList, zipUrl } return result } module.exports.exportProcessReportDocs = exportProcessReportDocs function renderReportDocsByTextbook(textbook){ let json = textbook.toJSON(); // 圆圈选中未选 ○ 未选 ● 选中 let circleCheck = ["○","●"]; // 方块选中未选 ○ 未选 ● 选中 let squareCheck = [``,`☑`]; // 联系电话:默认为作者首个存在的电话; let mobile = json?.authorList?.find(item => item.mobile)?.mobile || "" // 填报时间:默认为创建时间 let createdAt = new Date(textbook?.createdAt); let createdDate = `${createdAt?.getFullYear()}年${createdAt?.getMonth()+1}月${createdAt?.getDate()}日`; // 专业代码:前四位 let majorCode = json?.majorId || json?.major?.code if(majorCode?.length>4){ majorCode = majorCode.slice(0,4) } let majorName = json?.majorName || json?.major?.name // 是否重点立项 let isJC = circleCheck[(json?.approval?.indexOf("基础")>-1)?1:0]; let isZL = circleCheck[(json?.approval?.indexOf("战略")>-1)?1:0]; let isSX = circleCheck[(json?.approval?.indexOf("四新")>-1)?1:0]; let isNotImpt = (json?.approval?.indexOf("基础")==-1) && (json?.approval?.indexOf("战略")==-1) && (json?.approval?.indexOf("四新")==-1) isNotImpt = circleCheck[isNotImpt?1:0]; // 初版时间 let firstDate = new Date(textbook?.get("editionFirst")); let firstYear = firstDate?.getFullYear(); let firstMonth = firstDate?.getMonth()+1; // 本版时间印次 let currentDate = new Date(textbook?.get("editionDate")); let currentYear = currentDate?.getFullYear(); let currentMonth = currentDate?.getMonth()+1; // 最新时间印次 let latestDate = new Date(textbook?.get("printDate")); let latestYear = latestDate?.getFullYear(); let latestMonth = latestDate?.getMonth()+1; // 初版至今重点项目 let isBSQT = !((json?.importantProject?.indexOf("建设")>-1) || (json?.importantProject?.indexOf("本科国家")>-1) || (json?.importantProject?.indexOf("省级优秀")>-1) || (json?.importantProject?.indexOf("省级规划")>-1))// 是否其他省级奖项 let bookData = { // 封面信息 titlePad:padString(json?.title,21), ISBN:padString(json?.ISBN,21), one:squareCheck[(json?.type=="单本"||json?.type=="单册")?1:0], // 单本/单册 方框 full:squareCheck[json?.type=="全册"?1:0], // 全册 oneCircle:circleCheck[(json?.type=="单本"||json?.type=="单册")?1:0], // 单本/单册 圆圈 fullCircle:circleCheck[json?.type=="全册"?1:0], // 全册 tn:json?.typeNumber, authorPad:padString(json?.author,21), mobile:padString(mobile,21), authorUnit:padString(json?.unit,21), publisherPad:padString(json?.editionUnit,21), recommandUnit:padString("",21), // 未找到 majorCodePad:padString((majorCode),14), createdDate:padString(createdDate,21), // 基本信息 title:json?.title, author:json?.author, unit:json?.unit, mc:majorCode, mn:majorName, lCN:circleCheck[(json?.lang=="中文")?1:0], lEN:circleCheck[(json?.lang=="英文")?1:0], lOT:circleCheck[(json?.lang?.indexOf("其他")>-1)?1:0], lSS:circleCheck[(json?.lang?.indexOf("少数")>-1)?1:0], authors:json?.authors, // 其他主编 editor:json?.editor, // 其他编者 isJC:isJC, isZL:isZL, isSX:isSX, isNotImpt:isNotImpt, publisher:json?.editionUnit, firstYear:firstYear, firstMonth:firstMonth, isZZ:circleCheck[(json?.carrierShape?.indexOf("纸质")>-1)?1:0], isDZ:circleCheck[(json?.carrierShape?.indexOf("电子")>-1)?1:0], isSZ:circleCheck[(json?.carrierShape?.indexOf("数字")>-1)?1:0], isQT:circleCheck[(json?.carrierShape?.indexOf("附带")>-1)?1:0], isFD:circleCheck[(json?.carrierShape?.indexOf("其他")>-1)?1:0], latestY:latestYear, latestM:latestMonth, latestNum:json?.printNumber || "", currentY:currentYear, currentM:currentMonth, currentNum:json?.editionNumber || "", printSum:json?.printSum || "", isJS:circleCheck[(json?.importantProject?.indexOf("建设")>-1)?1:0], isBGJ:circleCheck[(json?.importantProject?.indexOf("本科国家")>-1)?1:0], isBSYX:circleCheck[(json?.importantProject?.indexOf("省级优秀")>-1)?1:0], isBSGH:circleCheck[(json?.importantProject?.indexOf("省级规划")>-1)?1:0], isBSQT:circleCheck[isBSQT?1:0], bsqtName:isBSQT?json?.importantProject:"", isFirstNot:circleCheck[json?.importantProject?0:1], } console.log(bookData) let bookid = json.code || json?.objectId; let tempFileName = path.join(`${bookid}${json.title}.docx`) return new Promise((resolve)=>{ replaceDocx(TemplateDocxPath,tempFileName,bookData,{onDocxComplete:async (filePath)=>{ // 需要API支持 // docsToPdf(filePath) let url = (await uploadFileToOSS(filePath))?.url || null resolve({ code:bookid, title:json?.title, filePath, url }) }}) }) } function padString(str,width) { str = str || "" str = String(str) width = width || 21 // 目标宽度为21个单位 spaceChar = " " // 占位符 // 计算字符串的宽度 let strWidth = 0; console.log(str) for (let char of str) { // 判断字符是否为中文 if (char.match(/[\u4e00-\u9fa5]/)) { strWidth += 2; // 中文字符占4个单位 } else { strWidth += 1; // 英文字符占1个单位 } } const totalPadding = width - strWidth; // 如果已经达到或超过目标宽度,直接返回原字符串 if (totalPadding <= 0) { return str; } // 计算左右两侧的空格数 const leftPadding = Math.floor(totalPadding / 2) * 3; const rightPadding = Math.ceil(totalPadding / 2) * 3; // 生成填充空格的字符串 const leftSpaces = spaceChar.repeat(leftPadding); const rightSpaces = spaceChar.repeat(rightPadding); // 返回补充后的字符串 return leftSpaces + str + rightSpaces; }