大家好,我正在使用 React.js 和 Node.js 开发一个网站,我根据用户的输入生成一个 Word 文档,这与 docxtemplater 配合得很好!
问题是我想让用户直接将word文档下载为PDF文档,但docxtemplater只允许我们将文件另存为docx。 为了转换docx,我有想法用gridfs将我的blob文档保存在mongodb中(已经完成并且工作正常),然后获取我的blob并将其转换为pdf(我被阻止的地方)
这是我的代码部分,用于生成我的docx并将生成的word docx保存在mongodb中(我故意删除了一些对这个问题不重要的东西)
import React, { useState, useEffect } from "react";
import Docxtemplater from "docxtemplater";
import PizZip from "pizzip";
import PizZipUtils from "pizzip/utils/index.js";
import { saveAs } from "file-saver";
import axios from "axios";
function loadFile(url, callback) {
PizZipUtils.getBinaryContent(url, callback);
}
export const DocxFile = ({ formData }) => {
const [file, setFile] = useState(null);
const [currentlyUploading, setCurrentlyUploading] = useState(false);
const [docxId, setDocxId] = useState(null);
const [progress, setProgress] = useState(null);
const [inputContainsFile, setInputContainsFile] = useState(false);
const [template, setTemplate] = useState();
const generateDocument = () => {
loadFile(template, function (error, content) {
if (error) {
throw error;
}
var zip = new PizZip(content);
var doc = new Docxtemplater(zip, {
paragraphLoop: true,
linebreaks: true,
});
doc.setData({
company: formData.general.companyClient,
version: formData.documentVersion,
quote: formData.general.quoteNumber,
HERE MY DATA //Working :)
});
try {
doc.render();
} catch (error) {
function replaceErrors(key, value) {
if (value instanceof Error) {
return Object.getOwnPropertyNames(value).reduce(function (
error,
key
) {
error[key] = value[key];
return error;
},
{});
}
return value;
}
if (error.properties && error.properties.errors instanceof Array) {
const errorMessages = error.properties.errors
.map(function (error) {
return error.properties.explanation;
})
.join("\n");
}
throw error;
}
var out = doc.getZip().generate({
type: "blob",
mimeType:
"application/vnd.openxmlformats-officedocument.wordprocessingml.document",
});
saveAs(
out,
`${name}.${documentVersion}.docx`
);
setFile(out);
setInputContainsFile(true);
});
};
const fileUploadHandler = () => {
const fd = new FormData();
fd.append("docx", file, file.name);
axios
.post(`api/docx/upload`, fd, {
onUploadProgress: (ProgressEvent) => {
setProgress((ProgressEvent.loaded / ProgressEvent.total) * 100);
console.log(
"upload progress",
Math.round((ProgressEvent.loaded / ProgressEvent.total) * 100)
);
},
})
.then(({ data }) => {
setDocxId(data);
setFile(null);
setInputContainsFile(false);
setCurrentlyUploading(false);
})
.catch((err) => {
console.log(err);
if (err.response.status === 400) {
const errMsg = err.response.data;
if (errMsg) {
console.log(errMsg);
}
} else {
console.log("other error", err);
setInputContainsFile(false);
setCurrentlyUploading(false);
}
});
};
const handleClick = () => {
if (inputContainsFile) {
setCurrentlyUploading(true);
fileUploadHandler();
}
};
return (
<>
<button
className="modify__button1 enregistrer generator__button"
onClick={generateDocument}
>
Generate the docx
</button>
<label htmlFor="file" onClick={handleClick}>
{file ? <>SUBMIT</> : <></>}
</label>
</>
);
};
之后,我将执行一个 get 请求来获取我的 blob(我已经知道如何获取我的 blob)但是,然后,我如何将其转换为 pdf(并保留用于我的 docx 的模板)?
我发现的最好的选择(无需在光盘上写入任何内容!)基于
libreoffice-convert
npm(您仍然需要在计算机上安装 libreoffice)。
现在我可以基于 docxtemplater 的相同模板轻松创建 DOCX 和 PDF ;-)
我的反应代码:
// In your controller or service:
export const exportTextToFile = async (text: string, filetype: string): Promise<Blob> => {
const exportToFileEndpointUrl = `${API_BASE_URL}/api/export/${filetype}`;
const response = await axios.post<ArrayBuffer>(exportToFileEndpointUrl, text, {
responseType: 'arraybuffer',
});
return new Blob([response.data]);
};
// In your component:
const getAndDownloadFile = async (filetype: string) => {
try {
const blob = await exportTextToFile(text, filetype);
saveAs(blob, `MyFile.${filetype}`);
} catch (error) {
console.error(error);
}
};
在 NodeJS 后端应用程序中:
import libre from 'libreoffice-convert';
try {
const docxBuffer = await generateDocx(...);
if (filetype === 'pdf') {
libre.convert(docxBuffer, 'pdf', undefined, (err, pdfBuffer) => {
if (err) {
throw err;
} else {
res.send(pdfBuffer);
}
});
} else if (filetype === 'docx') {
res.send(docxBuffer);
}
logger.info('Sent file buffer to the client', { filetype });
} catch (error) {
logger.error('Error during file creation', { filetype, error: error.message });
res.sendStatus(500);
}
// Your docxtemplater generator:
import Docxtemplater from 'docxtemplater';
function generateDocx(...): Promise<Buffer> {
const content = fs.readFileSync(path.resolve(__dirname, 'your-template.docx'), 'binary');
const zip = new PizZip(content);
const doc = new Docxtemplater(zip, {
paragraphLoop: true,
linebreaks: true,
});
doc.render({
/// your template params
});
const buffer = doc.getZip().generate({
type: 'nodebuffer',
compression: 'DEFLATE',
});
return buffer;
}