自学内容网 自学内容网

项目-02-数学学院后台项目开发过程中的问题总结

一、后台(pc端,vue2)

1. dialog对话框被黑色蒙层盖住

问题: dialog被黑色蒙层盖住(如下图),我希望dialog背景是黑色蒙层,但是dialog对话框不被盖住
在这里插入图片描述
解决办法: 给el-dialog添加如下两个属性

    <el-dialog 
      :modal-append-to-body="false" 
      :append-to-body="true">

添加后效果如下:
在这里插入图片描述

2. 将前端表格导出为word文档

需求:

  1. 前端独立完成
  2. 将审批通过的数据,按照班级分类打印出通过人员名单
  3. word文档的名字可以指定(前端人员传参决定),例如传参为“入团积极分子审查表”
  4. word文档的内容标题为动态的,是各期活动名字,例如“入团申请第十一期”
  5. word文档的后缀为.docx

效果图如下:

在这里插入图片描述

解决方法:
一. 参考文档

二. 具体方法

  1. 安装第三方包:
  • vue3下载包参考版本
"dependencies": {
    "angular-expressions": "^1.2.1",
    "docx-preview": "^0.3.2",
    "docxtemplater": "^3.49.1",
    "docxtemplater-image-module-free": "^1.1.1",
    "file-saver": "^2.0.5",
    "lodash": "^4.17.21",
    "pizzip": "^3.1.7",
  },

  • vue2下载包参考版本(docx-preview版本过高可能会报错)
"dependencies": {
    "angular-expressions": "^1.2.1",
    "docx-preview": "^0.1.20",
    "docxtemplater": "^3.49.1",
    "docxtemplater-image-module-free": "^1.1.1",
    "file-saver": "^2.0.5",
    "lodash": "^4.17.21",
    "pizzip": "^3.1.7",
  },
  1. 根据自己的需求,创建word文档,我创建的word文档如下:(具体书写规则参考vue3实现包含表格的Word文件导出里的解释)

在这里插入图片描述

  1. 编写导出Word的工具函数(我在utils文件夹下创建了exportFile.js文件)

注意:

  • 下面代码是完整版代码(包括word的 导出预览,导出功能包括支持图片导出和不支持图片导出)
  • 由于我只需要 “导出word,不支持图片” 的功能,所以最后只使用了下列代码中的exportWord函数,大家用的时候可以根据需要填写
// 编写导出word的工具函数

// 引入基本模块
import Docxtemplater from "docxtemplater";
import PizZip from "pizzip";
import PizZipUtils from "pizzip/utils/index.js";
import { saveAs } from "file-saver";
// 图片模块
import ImageModule from "docxtemplater-image-module-free";
// 解析语法模块
import expressions from "angular-expressions";
import assign from "lodash/assign";
// 文档预览模块
import { renderAsync } from "docx-preview";

expressions.filters.lower = function (input) {
  if (!input) return input;
  return input.toLowerCase();
};

function angularParser(tag) {
  tag = tag
    .replace(/^\.$/, "this")
    .replace(/('|')/g, "'")
    .replace(/("|")/g, '"');
  const expr = expressions.compile(tag);
  return {
    get: function (scope, context) {
      let obj = {};
      const scopeList = context.scopeList;
      const num = context.num;
      for (let i = 0, len = num + 1; i < len; i++) {
        obj = assign(obj, scopeList[i]);
      }
      return expr(scope, obj);
    },
  };
}

// 加载文件
function loadFile(url, callback) {
  PizZipUtils.getBinaryContent(url, callback);
}

// 配置空值替换函数 作为配置参数可配置在setOptions中
function nullGetter(part, scopeManager) {
  if (!part.module) {
    return "-null-";
  }
  if (part.module === "rawxml") {
    return "";
  }
  return "--";
}

/**
 * 预览word,支持图片
 * @param {Object} tempDocxPath 模板文件路径
 * @param {Object} wordData 导出数据
 * @param {Object} fileName 导出文件名
 * @param {Arrsy} imgSize 自定义图片尺寸
 */
export const getWordImage = (tempDocxPath, wordData, imgSize, file) => {
  loadFile(tempDocxPath, (error, content) => {
    if (error) {
      throw error;
    }

    // 图片配置
    const imageOpts = {
      getImage: function (tagValue, tagName) {
        return new Promise(function (resolve, reject) {
          PizZipUtils.getBinaryContent(tagValue, function (error, content) {
            if (error) {
              return reject(error);
            }
            return resolve(content);
          });
        });
      },
      getSize: function (img, tagValue, tagName) {
        const size = imgSize[tagName] ? imgSize[tagName] : [150, 150];
        return size;
      },
    };

    let imageModule = new ImageModule(imageOpts);

    const zip = new PizZip(content);

    // 实例化有两种方式 这里是链式
    const doc = new Docxtemplater()
      .loadZip(zip)
      .setOptions({
        // delimiters: { start: "[[", end: "]]" },
        paragraphLoop: true,
        linebreaks: true,
        nullGetter: nullGetter,
        parser: angularParser,
      })
      .attachModule(imageModule)
      .compile();

    doc.renderAsync(wordData).then(() => {
      const out = doc.getZip().generate({
        type: "blob",
        mimeType:
          "application/vnd.openxmlformats-officedocument.wordprocessingml.document",
      });
      renderAsync(out, file);
    });
  });
};



/**
 * 导出word,不支持图片
 * @param {Object} tempDocxPath 模板文件路径
 * @param {Object} wordData 导出数据
 * @param {Object} fileName 导出文件名
 */
export const exportWord = (tempDocxPath, wordData, fileName) => {
  loadFile(tempDocxPath, (error, content) => {
    if (error) {
      throw error;
    }
    const zip = new PizZip(content);
    const doc = new Docxtemplater().loadZip(zip)
    doc.setData({
      ...wordData.form,
      user_list: wordData.user_list,
      outsideList: wordData.outsideList
    })

    try {
      doc.render()
    } catch (error) {
      const e = {
        message: error.message,
        name: error.name,
        stack: error.stack,
        properties: error.properties
      }
      throw error
    }

    const out = doc.getZip().generate({
      type: "blob",
      mimeType:
        "application/vnd.openxmlformats-officedocument.wordprocessingml.document",
    });
    // Output the document using Data-URI
    saveAs(out, `${fileName}.docx`);
  });
}

/**
 * 导出word,支持图片
 * @param {Object} tempDocxPath 模板文件路径
 * @param {Object} wordData 导出数据
 * @param {Object} fileName 导出文件名
 * @param {Arrsy} imgSize 自定义图片尺寸
 */
export const exportWordImage = (tempDocxPath, wordData, fileName, imgSize) => {
  loadFile(tempDocxPath, (error, content) => {
    if (error) {
      throw error;
    }

    // 图片配置
    const imageOpts = {
      getImage: function (tagValue, tagName) {
        return new Promise(function (resolve, reject) {
          PizZipUtils.getBinaryContent(tagValue, function (error, content) {
            if (error) {
              return reject(error);
            }
            return resolve(content);
          });
        });
      },
      getSize: function (img, tagValue, tagName) {
        const size = imgSize[tagName] ? imgSize[tagName] : [150, 150]
        return size;
      },
    };

    let imageModule = new ImageModule(imageOpts);

    const zip = new PizZip(content);

    // 实例化有两种方式 这里是链式
    const doc = new Docxtemplater()
      .loadZip(zip)
      .setOptions({
        // delimiters: { start: "[[", end: "]]" },
        paragraphLoop: true,
        linebreaks: true,
        nullGetter: nullGetter,
        parser: angularParser,
      })
      .attachModule(imageModule)
      .compile();

    doc.renderAsync(wordData).then(function () {
      const out = doc.getZip().generate({
        type: "blob",
        mimeType:
          "application/vnd.openxmlformats-officedocument.wordprocessingml.document",
      });
      saveAs(out, `${fileName}.docx`);
    });
  });
}


  1. vue页面使用
import { exportWord } from '../../utils/exportFile';

export default {
data() {
return {
activity_name: '入团积极分子第十一期',
filename: '入团积极分子审查表'
}
},
methods: {
exportTable() {
// 需要导出的所有数据都需要写在wordData里面
// 因为我们写的exportWord工具函数只接受三个参数,第一个是模版文件路径,第二个是导出数据,第三个是表的名称
// 当然,大家也可以根据需要修改../../utils/exportFile里面的函数
let wordData = { 
form: {
activity_name: this.activity_name // 活动名称
},
outsideList: [ // 要导出的班级人员名单数据
      {
        user_class: '计科211',
        user_list: [
          { name: '袁云熙'},
          { name: '莫睿'}
        ]
      },
      {
        user_class: '数本221',
        user_list: [
          { name: '向致远'}
        ]
      }
    ]
}
exportWord("../../../static/template.docx", wordData, this.filename)
}
}
}

3. 在线查看、下载 .docx、.doc、.pdf文档

需求:

  1. 前端独立完成
  2. 后端返回的是文件地址,例如:
  3. 点击“查看”按钮,在新窗口打开查看文档内容
  4. 点击“下载”按钮,可以下载对应的文档
  5. 点击“一键导出”,可以下载全部的文档

参考文档:

解决方案:

<div class="top">
  <el-button @click="downAllfile" style="padding: 3px 0" type="text">一键导出</el-button>
</div>

<el-table :data="wordPdfData" border>
    <el-table-column label="操作" align="center" width="250">
      <template #default="{ row }">
        <span class="check">
          <a :href="getFileExtension(row.file_name) === 'pdf' ? `${row.file_path}` : `https://view.officeapps.live.com/op/view.aspx?src=${row.file_path}`" target="_blank">查看</a>
        </span>
        <span class="download">
          <a @click="downFile(row.file_path, row.file_name)">下载</a>
        </span>
      </template>
    </el-table-column>
</el-table>
export default {
data() {
return {
wordPdfData: []
}
},
methods: {
// 获取文件后缀名
    getFileExtension(filename) {
      return filename.split('.').pop().toLowerCase()
    },
    // 下载文件
    downFile(url, filename) { // url:文件地址,filename:文件名称
      return new Promise((resolve, reject) => {
        // 创建一个隐藏的<a>元素用于触发下载
        const a = document.createElement("a");
        
        // 使用fetch API下载文件
        fetch(url)
          .then(res => {
            // 检查网络响应是否成功
            if (!res.ok) {
              // 如果响应不成功,则抛出一个错误
              throw new Error(`网络响应失败,状态码:${res.status}`);
            }
            // 如果响应成功,则返回Blob对象
            return res.blob();
          })
          .then(blob => {
            // 创建一个对象URL用于下载
            const objectURL = URL.createObjectURL(blob);
            a.href = objectURL;
            a.download = filename; // 设置下载的文件名
            a.style.display = 'none'; // 隐藏<a>元素
            document.body.appendChild(a); // 将<a>元素添加到文档中
            a.click(); // 触发下载
            
            // 使用setTimeout在下一轮事件循环中释放对象URL并移除<a>元素
            // 同时解析Promise表示下载成功
            setTimeout(() => {
              URL.revokeObjectURL(objectURL);
              document.body.removeChild(a);
              resolve(); // 下载成功,解析Promise
            }, 0);
          })
          .catch(error => {
            // 如果在下载过程中发生错误,则拒绝Promise
            reject(error); // 下载失败,拒绝Promise
          });
      });
    },
    // 批量下载文件
    downAllfile() {
      let downList = this.wordPdfData

      const downloadPromises = downList.map(item => {
        const downloadUrl = item.file_path; // 构造下载URL
        return new Promise((resolve, reject) => {
          // 调用downImage方法下载图片,并在下载完成后解析或拒绝Promise
          this.downFile(downloadUrl, item.file_name)
            .then(() => resolve()) 
            .catch(error => reject(error)); 
        });
      })
 
      // 使用Promise.all等待所有下载任务完成
      Promise.all(downloadPromises)
        .then(() => {
          // 所有文件都已成功下载
          this.$message({
            type: 'success',
            message: '所有导出成功!',
            showClose: true,
            duration: 3000
          });
        })
        .catch(error => {
          // 至少有一个文件下载失败
          console.error('至少有一个文件下载失败:', error);
          this.$message({
            type: 'error',
            message: '导出失败,请重试。',
            showClose: true,
            duration: 3000
          });
        });
    }    
}
}

原文地址:https://blog.csdn.net/m0_64150479/article/details/144249514

免责声明:本站文章内容转载自网络资源,如本站内容侵犯了原著者的合法权益,可联系本站删除。更多内容请关注自学内容网(zxcms.com)!