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

news2025/2/25 0:34:39

目录

  • 一、后台(pc端,vue2)
      • 1. dialog对话框被黑色蒙层盖住
      • 2. 将前端表格导出为word文档
      • 3. 在线查看、下载 .docx、.doc、.pdf文档

一、后台(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

效果图如下:

在这里插入图片描述

解决方法:
一. 参考文档

  • vue3实现包含表格的Word文件导出
  • Vue中前端导出word文件

二. 具体方法

  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. 点击“一键导出”,可以下载全部的文档

参考文档:

  • 纯前端vue在线预览编辑Office,支持doc/docx、xls/xlsx、ptt/pttx、pdf等格式

解决方案:

<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
	          });
	        });
	    }	    
	}
}

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/2253422.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

大数据实验E5HBase:安装配置,shell 命令和Java API使用

实验目的 熟悉HBase操作常用的shell 命令和Java API使用&#xff1b; 实验要求 掌握HBase的基本操作命令和函数接口的使用&#xff1b; 实验平台 操作系统&#xff1a;Linux&#xff08;建议Ubuntu16.04或者CentOS 7 以上&#xff09;&#xff1b;Hadoop版本&#xff1a;3…

使用Tomcat搭建简易文件服务器

创建服务器 1. 复制一个tomcat服务器&#xff0c;并命名为file-service(好区分即可) 2.在webapp里面新建一个文件夹 uploadfiles ,用于存储上传的文件 3. 修改conf/service.xml,配置文件服务器的端口与上传文件夹的访问 在Host标签之间加入一个Context标签 docBase"uploa…

【算法】位运算合集

阿华代码&#xff0c;不是逆风&#xff0c;就是我疯 你们的点赞收藏是我前进最大的动力&#xff01;&#xff01; 希望本文内容能够帮助到你&#xff01;&#xff01; 目录 零&#xff1a;位运算基础公式 零&#xff1a;五道基础题 1&#xff1a;位1的个数 2&#xff1a;比…

【NLP高频面题 - LLM架构篇】旋转位置编码RoPE相对正弦位置编码有哪些优势?

【NLP高频面题 - LLM架构篇】旋转位置编码RoPE相对正弦位置编码有哪些优势&#xff1f; 重要性&#xff1a;⭐⭐⭐ &#x1f4af; NLP Github 项目&#xff1a; NLP 项目实践&#xff1a;fasterai/nlp-project-practice 介绍&#xff1a;该仓库围绕着 NLP 任务模型的设计、训练…

《Vue零基础教程》(5)计算属性和侦听器好讲解

1 计算属性 1) 什么是计算属性 计算属性就是基于现有属性计算后的属性 2) 计算属性的作用 计算属性用于对原始数据的再次加工 3) 案例 需求 实现如下效果 使用表达式实现 <!DOCTYPE html> <html lang"en"><head><meta charset"UTF…

Narya.ai正在寻找iOS工程师!#Mixlab内推

如果你对AI技术和iOS开发充满热情&#xff0c;这里有一个绝佳的机会加入一家专注于AI应用创新的初创公司。Narya.ai正在招聘iOS工程师&#xff0c;帮助他们开发下一代效率工具&#xff0c;旨在提升用户的日常生活效率与幸福感。 关于Narya.ai&#xff1a; 专注于AI应用层创新&a…

【开源免费】基于SpringBoot+Vue.JS课程答疑系统(JAVA毕业设计)

博主说明&#xff1a;本文项目编号 T 070 &#xff0c;文末自助获取源码 \color{red}{T070&#xff0c;文末自助获取源码} T070&#xff0c;文末自助获取源码 目录 一、系统介绍二、演示录屏三、启动教程四、功能截图五、文案资料5.1 选题背景5.2 国内外研究现状5.3 可行性分析…

FPGA实战篇(触摸按键控制LED灯)

1.触摸按键简介 触摸按键主要可分为四大类&#xff1a;电阻式、电容式、红外感应式以及表面声波式。根据其属性的不同&#xff0c;每种触摸按键都有其合适的使用领域。 电阻式触摸按键由多块导电薄膜按照按键的位置印制而成&#xff0c;但由于耐用性较差且维护复杂&#xff0c…

VSCode如何关闭Vite项目本地自启动

某些情况下VSCode打开Vite项目不需要自动启动&#xff0c;那么如何关闭该功能 文件>首选项>设置 搜索vite 将Vite:Auto Start 勾选取消即可

重生之我在异世界学编程之C语言:深入指针篇(上)

大家好&#xff0c;这里是小编的博客频道 小编的博客&#xff1a;就爱学编程 很高兴在CSDN这个大家庭与大家相识&#xff0c;希望能在这里与大家共同进步&#xff0c;共同收获更好的自己&#xff01;&#xff01;&#xff01; 本文目录 引言正文&#xff08;1&#xff09;内置数…

TypeScript (一)运行环境配置,数据类型,可选类型,联合类型,type与interface,交叉类型,断言as,字面量类型,类型缩小

文章目录 一、认识TS1.1 JS 存在的问题1.2 TS的出现1.3 TS运行环境运行ts的三种方式 1.4 变量声明1.5 类型推断 二、数据类型2.1 JS数据类型(1) 数组Array(2) 对象Object(3) 其他类型 2.2 TS特有数据类型(1) any类型(2) unknown类型(3) void类型(4) never (了解)(5) tuple类型 …

【Leetcode 每日一题】3274. 检查棋盘方格颜色是否相同

问题背景 给你两个字符串 c o o r d i n a t e 1 coordinate1 coordinate1 和 c o o r d i n a t e 2 coordinate2 coordinate2&#xff0c;代表 8 8 8 \times 8 88 国际象棋棋盘上的两个方格的坐标。 以下是棋盘的参考图。 如果这两个方格颜色相同&#xff0c;返回 t …

【Dubbo03】消息队列与微服务之dubbo-admin 二进制与编译安装

实战案例&#xff1a;二进制安装 dubbo-admin 新版用Golang重构&#xff0c;提供了二进制包&#xff0c;可以直接部署 #下载二进制包 [rootubuntu2204 ~]#wget https://github.com/apache/dubbo-admin/releases/download/0.5.0/apache-dubbo-admin-0.5.0-bin-release.tar.gz …

Kylin Server V10 下 Kafka 集群部署

一、ZooKeeper 集群部署 1、主机规划 主机名 IP 地址 myid 10.8.3.35 1 10.8.3.36 2 10.8.3.37 3 2、拓扑结构 3、部署 (1) 下载Zookeeper [root@localhost ~]# cd /usr/local [root@localhost local]# wget https://www.apache.org/dyn/closer.lua/zookeeper/zookeeper-…

redis的应用----缓存

redis的应用----缓存 一、缓存的概念二、使用redis作为缓存2.1使用redis作为缓存的原因2.2缓存机制的访问步骤 三、缓存的更新策略3.1定期更新3.2实时更新3.3淘汰策略 四、缓存常见的问题4.1缓存预热(Cache preheating)4.2缓存穿透(Cache penetration)4.3缓存雪崩(Cache avalan…

用于LiDAR测量的1.58um单芯片MOPA(一)

--翻译自M. Faugeron、M. Krakowski1等人2014年的文章 1.简介 如今&#xff0c;人们对高功率半导体器件的兴趣日益浓厚&#xff0c;这些器件主要用于遥测、激光雷达系统或自由空间通信等应用。与固态激光器相比&#xff0c;半导体器件更紧凑且功耗更低&#xff0c;这在低功率供…

SpringBoot两天

SpringBoot讲义 什么是SpringBoot&#xff1f; Spring Boot是由Pivotal团队提供的全新框架&#xff0c;其设计目的是用来简化新Spring应用的初始搭建以及开发过程。该框架使用了特定的方式来进行配置&#xff0c;从而使开发人员不再需要定义样板化的配置。通过这种方式&#xf…

vue3项目最新eslint9+prettier+husky+stylelint+vscode配置

一、eslint9和prettier通用配置 安装必装插件 ESlint9.x pnpm add eslintlatest -DESlint配置 vue 规则 , typescript解析器 pnpm add eslint-plugin-vue typescript-eslint -DESlint配置 JavaScript 规则 pnpm add eslint/js -D配置所有全局变量 globals pnpm add globa…

LSTM-CNN-BP-RF-SVM五模型咖喱融合策略混合预测模型

目录 效果一览基本介绍程序设计参考资料 效果一览 基本介绍 LSTM-CNN-BP-RF-SVM五模型咖喱融合策略混合预测模型 Matlab代码注释清晰。 程序设计 完整程序和数据获取方式&#xff1a;私信博主回复LSTM-CNN-BP-RF-SVM五模型咖喱融合策略混合预测模型&#xff08;Matlab&#…

【数据集】细胞数据集:肿瘤-胎儿重编程的内皮细胞驱动肝细胞癌中的免疫抑制性巨噬细胞(Sharma等人)

引用此数据集&#xff1a; Sharma, Ankur (2020), “Onco-fetal reprogramming of endothelial cells drives immunosuppressive macrophages in Hepatocellular Carcinoma (Sharma et al)”, Mendeley Data, V1, doi: 10.17632/6wmzcskt6k.1 下载地址&#xff1a;Onco-feta…