业务背景
最近在开发的过程中,接到了一个需求如下
也就是说,后端的业务要支持对这个报告的生产,前端需要能支持下载这个文档。
那么我们如何解这个问题呢?
后端(基于express框架)
使用docxtemplater
第一步,我们需要使用docxtemplater和pizzip
npm install docxtemplater pizzip
然后把希望用到的,要生成的word文档写入模版word文档中
文档内容的渲染规则举例如下:
word文档
js code
其中 {startTime} 用于替换单个变量, {#projects} {/projects} 用于渲染数组,也就是说变量 projects是一个对象数组,每一项有date和hour两个属性。
完整代码如下
const PizZip = require("pizzip");
const Docxtemplater = require("docxtemplater");
const fs = require("fs");
const time = require("../until/time");
const path = require("path");
function renderWord(data, type, outputName) {
// Load the docx file as binary content
const content = fs.readFileSync(
path.resolve(`public/template/${type}.docx`),
"binary"
);
const zip = new PizZip(content);
const doc = new Docxtemplater(zip, {
paragraphLoop: true,
linebreaks: true,
});
// Render the document (Replace {first_name} by John, {last_name} by Doe, ...)
if (type === "totalHour") {
doc.render({
userId: data.userId,
startTime: data.startTime,
endTime: data.endTime,
totalHour: data.totalHour,
});
} else if (type === "projectHour") {
console.log(data.projects);
doc.render({
projectName: data.projectName,
startTime: data.startTime,
endTime: data.endTime,
projects: data.projects,
});
} else if (type === "vocation") {
doc.render({
vocation: data.vocation,
});
} else if (type === "salary") {
doc.render({
userId: data.userId,
salaries: data.salaries,
});
}
const buf = doc.getZip().generate({
type: "nodebuffer",
compression: "DEFLATE",
});
const random = time.getCurrentTimeInBeijing().replace(" ", "T");
fs.writeFileSync(
path.resolve(`public/report/${random}-${outputName}.docx`),
buf
);
console.log(`${random}-${outputName}.docx`);
return `${random}-${outputName}.docx`;
}
module.exports = {
renderWord,
};
这里生产的文件名为了防止重复,加上了时间戳前缀,这部分可以自行按需实现random。生成的文件都放到目录 public/report 下生成文档后将对应的文件名返回给前端。
后端启用访问静态资源的中间件
app.use("/static", express.static(path.join(__dirname, "public")));
这样我们在前端组装链接如下即可:
`http://{domain}/static/report/{filename}`