根据数据生成pdf有两个比较好用的包,officegen是采用api的方式生成word、docxtemplater是使用docx文件模版的方式生成word。个人觉得docxtemplater更加方便,对图片,格式支持的更加完善
officegen
- 创建 Word 文档。
- 您可以在文档中添加一个或多个段落,并且可以设置字体、颜色、对齐方式等。
- 您可以添加图像。
- 支持页眉和页脚。
- 支持书签和超链接。
// 代码示例
const officegen = require('officegen');
let docx = officegen('docx');
async createWord(ctx) {
const postData = ctx.request.body;
const { data, fileName } = postData; // 拿到需要渲染的数据
docx.on('finalize', function (written) { // 监听创建结束
console.log(
'Finish to create a Microsoft Word document.'
)
})
docx.on('error', function (err) { // 监听生成失败
console.log(err)
})
let pObj = docx.createP() // 创建一个页面
// pObj.addImage(path.resolve(__dirname, 'myFile.png'), {cx: 300, cy: 200}) // 添加一张图片(目前没生效)
// docx.putPageBreak() // 结束当前页
pObj = docx.createP() // 创建一个新页面
data.forEach((item, index) => { // 循环数据添加文本
pObj.addLineBreak(); // 添加一个空行
item.user && pObj.addText('账号:' + (item.user?.screen_name || '用户' + item.user?.id + ', ')); // 添加一段文案
pObj.addLineBreak(); // 添加一个空行
item.fav_count && pObj.addText('收藏:' + item.fav_count + ', ', { blod: true, font_face: '宋体', font_size: 12 }); // 添加一段文案含样式
pObj.addLineBreak();
})
let out = fs.createWriteStream(fileName + '.docx');
out.on('error', function (err) {
console.log(err)
})
docx.generate(out) //将docx灌到可写流中
ctx.body = { // 返回
result_code: 0,
url: fileName + '.docx',
state: 'success',
};
}
async downloadFild(ctx) { // 导出并删除文件
const fileName = ctx.query.path;
ctx.attachment(path.resolve(__dirname, fileName));
await send(ctx, path);
setTimeout(() => {
// 删除文件
fs.unlink(path.resolve(__dirname, fileName), (err) => {
console.log('文件已被删除');
});
}, 15000);
}
附上文档: https://github.com/Ziv-Barber/officegen/blob/master/manual/docx/README.md
docxtemplater
- 它的工作方式与模板引擎相同,你给它一个模板+一些数据,它会输出一个生成的文档。
- 可以抽象地处理循环、条件和其他功能
- 可以使用 docxtemplater-image-module 模块来插入图片
- 可以使用 docxtemplater-html 模块插入超链接(模块需要付费)
- 排版字体等以模版为准,代码不需要关注
input.docx模版文件部分截图
image.png
image.png
// 代码示例
const Docxtemplater = require("docxtemplater");
const PizZip = require("pizzip");
async createDocx(ctx) {
const postData = ctx.request.body
const { data, fileName, screenName,
start_day,
end_day,
} = postData;
const content = fs.readFileSync( // 创建可读流,读取docx模版
path.resolve(__dirname, "input.docx"),
"binary"
);
const zip = new PizZip(content); // 压缩
const doc = new Docxtemplater(zip, { //
paragraphLoop: true,
linebreaks: true,
});
const formatedData = data.map((item, index) => {
let temp = JSON.parse(JSON.stringify(item));
if (temp.user) {
temp.user = temp.status_type !== '资讯' ? (temp.user?.screen_name || '用户' + temp.user?.id) : '资讯'
}
return temp;
})
doc.render({ data: formatedData, screenName, start_day, end_day, curDate: moment().format('YYYY年MM月DD日 HH:mm:ss') });// 渲染相关数据到模版中
const buf = doc.getZip().generate({ // 解压并生成对应buf
type: "nodebuffer",
compression: "DEFLATE",
});
let upStream = fs.createWriteStream(fileName + '.docx'); // 创建可写流
upStream.write(buf);。// 将生成的buf写入文件
upStream.end();
upStream.on('close', () => {
console.log('写入的文件路径是' + upStream.path)
})
ctx.body = { //返回
result_code: 0,
url: upStream.path,
state: 'success',
};
}
网友评论