|
@@ -0,0 +1,146 @@
|
|
|
+import Docxtemplater from "docxtemplater";
|
|
|
+import PizZip from "pizzip";
|
|
|
+import PizZipUtils from "pizzip/utils/index.js";
|
|
|
+import ImageModule from 'docxtemplater-image-module-free';
|
|
|
+import { ElMessage } from 'element-plus';
|
|
|
+import { saveAs } from "file-saver";
|
|
|
+
|
|
|
+class ExportWord {
|
|
|
+ public url: string;
|
|
|
+ public fileName: string;
|
|
|
+ public data: any;
|
|
|
+ public docContent: Docxtemplater;
|
|
|
+
|
|
|
+ constructor(option) {
|
|
|
+ this.url = option.url;
|
|
|
+ this.fileName = option.filename;
|
|
|
+ this.data = option.obj;
|
|
|
+ }
|
|
|
+
|
|
|
+ // 初始化 Word 文档
|
|
|
+ async initWord(_callback) {
|
|
|
+ try {
|
|
|
+ const _content = await this.loadFile(this.url);
|
|
|
+ await this.setPizZip(_content);
|
|
|
+ _callback(this);
|
|
|
+ } catch (err) {
|
|
|
+ ElMessage.error('下载异常,请重试');
|
|
|
+ console.error('下载异常,请重试', err);
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ // 读取并获得模板文件的二进制内容
|
|
|
+ loadFile(url: string): Promise<any> {
|
|
|
+ return new Promise((resolve, reject) => {
|
|
|
+ PizZipUtils.getBinaryContent(url, (error, content) => {
|
|
|
+ if (error) {
|
|
|
+ reject(new Error('加载模板文件失败'));
|
|
|
+ } else {
|
|
|
+ resolve(content);
|
|
|
+ }
|
|
|
+ });
|
|
|
+ });
|
|
|
+ }
|
|
|
+
|
|
|
+ // 创建一个JSZip实例,内容为模板的内容
|
|
|
+ async setPizZip(_content) {
|
|
|
+ const imageOpts = {
|
|
|
+ getImage: function (tagValue, tagName) {
|
|
|
+ return new Promise((resolve, reject) => {
|
|
|
+ // 检查 tagValue 是否有效
|
|
|
+ if (!tagValue) {
|
|
|
+ console.error(`图片路径无效:${tagValue}`);
|
|
|
+ reject(new Error(`无效的图片路径: ${tagValue}`));
|
|
|
+ return;
|
|
|
+ }
|
|
|
+
|
|
|
+ // 读取二进制内容
|
|
|
+ PizZipUtils.getBinaryContent(tagValue, (error, content) => {
|
|
|
+ if (error) {
|
|
|
+ console.error(`加载图片失败: ${tagValue}`, error);
|
|
|
+ reject(new Error(`加载图片失败: ${tagValue}`));
|
|
|
+ } else {
|
|
|
+ console.log(`成功加载图片: ${tagValue}`);
|
|
|
+ resolve(content); // 返回图片的二进制内容
|
|
|
+ }
|
|
|
+ });
|
|
|
+ });
|
|
|
+ },
|
|
|
+ getSize: (img, tagValue, tagName) => {
|
|
|
+ return new Promise((resolve, reject) => {
|
|
|
+ const image = new Image();
|
|
|
+ image.src = tagValue;
|
|
|
+ image.onload = function () {
|
|
|
+ resolve([image.width, image.height]);
|
|
|
+ };
|
|
|
+ image.onerror = function (e) {
|
|
|
+ console.log("img, tagValue, tagName : ", img, tagValue, tagName);
|
|
|
+ alert("图片加载失败: " + tagValue);
|
|
|
+ reject(e);
|
|
|
+ };
|
|
|
+ });
|
|
|
+ }
|
|
|
+ };
|
|
|
+ const zip = new PizZip(_content);
|
|
|
+ this.docContent = new Docxtemplater(zip, {
|
|
|
+ modules: [new ImageModule(imageOpts)],
|
|
|
+ paragraphLoop: true,
|
|
|
+ linebreaks: true
|
|
|
+ });
|
|
|
+ console.log(this.data)
|
|
|
+ await this.setTemplateContent(this.data); // 确保模板内容设置完毕
|
|
|
+ }
|
|
|
+
|
|
|
+ // 设置模板内容
|
|
|
+ async setTemplateContent(_obj) {
|
|
|
+ try {
|
|
|
+ console.log(_obj)
|
|
|
+ await this.docContent.renderAsync(_obj); // 使用异步渲染方法替换模板中的变量
|
|
|
+ } catch (error: any) {
|
|
|
+ this.handleRenderError(error);
|
|
|
+ throw new Error("模板渲染失败");
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ // 错误处理
|
|
|
+ handleRenderError(error: any) {
|
|
|
+ function replaceErrors(key: any, value: any) {
|
|
|
+ if (value instanceof Error) {
|
|
|
+ return Object.getOwnPropertyNames(value).reduce(function (error: any, key: string) {
|
|
|
+ error[key] = value[key as keyof Error];
|
|
|
+ return error;
|
|
|
+ }, {});
|
|
|
+ }
|
|
|
+ return value;
|
|
|
+ }
|
|
|
+
|
|
|
+ console.log("渲染错误: ", JSON.stringify({ error }, replaceErrors));
|
|
|
+
|
|
|
+ if (error.properties && error.properties.errors instanceof Array) {
|
|
|
+ const errorMessages = error.properties.errors
|
|
|
+ .map((err: any) => err.properties.explanation)
|
|
|
+ .join("\n");
|
|
|
+ console.log("详细错误信息: ", errorMessages);
|
|
|
+ alert(`模板渲染错误: ${errorMessages}`);
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ // 下载文件
|
|
|
+ downloadFile() {
|
|
|
+ const out = this.docContent.getZip().generate({
|
|
|
+ type: "blob",
|
|
|
+ mimeType: "application/vnd.openxmlformats-officedocument.wordprocessingml.document"
|
|
|
+ });
|
|
|
+ saveAs(out, this.fileName);
|
|
|
+ }
|
|
|
+
|
|
|
+ addDownloadFile() {
|
|
|
+ const out = this.docContent.getZip().generate({
|
|
|
+ type: "blob",
|
|
|
+ mimeType: "application/vnd.openxmlformats-officedocument.wordprocessingml.document"
|
|
|
+ });
|
|
|
+ return out;
|
|
|
+ }
|
|
|
+}
|
|
|
+
|
|
|
+export default ExportWord;
|