一、效果

二、 需求

根据表格中的开票名称的金额,生成对应的单位对账函,然后发给各单位的负责人进行审核。由于word模板样式一致,故可用模板填充数据,进行企业对账函的一次性生成

三、前端vue技术

前端采用vue、avue、elementUI 技术

1、前端主要代码

<template><div style="padding: 20px"><div style="display: flex"><div style="margin-right: 20px"><el-upload:show-file-list="false"action="action":on-change="handleChange"><el-button type="primary">上传销售金额Excel</el-button></el-upload></div><div style="margin-right: 20px"><el-date-pickerv-model="daterange"type="daterange"range-separator="至"start-placeholder="开始日期"format="yyyy年MM月dd日"value-format="yyyy年MM月dd日"end-placeholder="结束日期"></el-date-picker></div><el-button type="primary" @click="createWordFiles">生成对账函</el-button></div><avue-crud :data="data" :option="option" ref="crud"></avue-crud></div>
</template>
<script>
import { createWordFilesApi } from "../api/api";
export default {data() {return {data: [],daterange: [],title: "",option: {index: true,menu: false,addBtn: false,page: false,column: [{label: "单位",prop: "company",},{label: "金额",prop: "totalPrice",},{label: "开票名称",prop: "ticketName",},],},};},methods: {handleChange(file, fileLis) {this.$export.xlsx(file.raw).then((data) => {console.log("data", data);this.title = data.header[0];let re = data.results;let result = [];for (let i = 1; i < re.length; i++) {let item = re[i];result.push({company: item[this.title],totalPrice: item.__EMPTY,ticketName: item.__EMPTY_1 ? item.__EMPTY_1 : "",});}this.data = result;});},createWordFiles() {let params = {title: this.title,data: JSON.stringify(this.data),startDate: this.daterange[0],endDate: this.daterange[1],};createWordFilesApi(params).then((res) => {console.log('res: ', res);let  data =res.data.data;let a = document.createElement('a');a.style.display='none';a.href="http://localhost/upload"+data.fileUrl;a.download = data.fileName;document.body.append(a);a.click();console.log("我单击了a标签")document.body.removeChild(a)// this.$message({//   type: "success",//   message: "生成成功!",// });}).catch((res)=>{console.log('fail-res: ', res);});},},
};
</script>
<style>
</style>

四、nodejs 技术

express +nodejs

1、生成文件并压缩文件夹

var fs = require("fs");
var util = require("../public/util");const PizZip = require("pizzip");
const Docxtemplater = require("docxtemplater");
const path = require("path");const archiver = require("archiver");const compressing = require("compressing");var fstream = require("fstream");
var zlib = require("zlib");
var tar = require("tar");let info = {createWordFilesApi: async function (req, res) {let result = req.body;let floderName = result.title + "-" + util.getNowFormatDate();let floder = "./企业对账函/" + floderName;let path = floder + "/";//生成文件夹目录fs.mkdirSync(path);// 加载docx模板 注意:只能用docx后缀名,如果为doc后缀名,需手动另存为docxconst content = fs.readFileSync("./word.docx", "binary");//生成docx文档let fileData = JSON.parse(result.data);for (let i = 0; i < fileData.length; i++) {let item = fileData[i];//注意:let zip = new PizZip(content); 需每次实例化,不然渲染出来所有的文件都为第一条数据let zip = new PizZip(content);let doc = new Docxtemplater(zip);//设置参数doc.setData({ticketName: item.ticketName ? item.ticketName : item.company,totalPrice: item.totalPrice,uppercaseTotalPrice: util.transCnMoney(item.totalPrice),startDate: result.startDate,endDate: result.endDate,});// 渲染doc.render();// 导出数据const buf = doc.getZip().generate({ type: "nodebuffer" });fs.writeFileSync(path + item.company + ".docx", buf);}let downLoadFile = floder + "-对账函.tgz";//压缩文件 因为需下载生成的压缩文件,故采用gzip压缩,试了其他两种压缩方式,均未能正常下载tar.c({gzip: true,file: downLoadFile,},[floder]).then(() => {let data = {};data.code = "200";data.data = {fileName: floderName + "-对账函.zip",fileUrl: "/" + downLoadFile.split("./")[1],};data.message = "生成文件夹成功";res.send(data);});// const output = fs.createWriteStream(downLoadFile);// // const archive = archiver("zip", {// //   zlib: { level: 9 }, // Sets the compression level.// // });// const archive = archiver("tar", {//     gzip:true,//     gzipOptions:{//         level: 9//     }// });// archive.pipe(output);// archive.directory(path, false);// archive.finalize();//await compressing.tgz.compressDir(floder, downLoadFile)//  let data = {};//     data.code = "200";//     data.data = {//         fileName: floderName + "-对账函.zip",//         fileUrl: "/" + downLoadFile.split("./")[1],//     };//     data.message = "生成文件夹成功";//     res.send(data);},
};module.exports = info;

2、下载文件

const path = require('path')
let express = require('express')
let fs = require('fs')
var mime = require('mime');
let router = express.Router()router.get('/*', (req,res) => {var filePath = "./"+req.params["0"];//  var filePath = "./企业对账函/2022年1月份销售-20220211083510-对账函.zip";
//     console.log('filePath: ', filePath);
//  console.log('download');
//  var f=filePath;
//   //var f = req.params[0];
//   f = path.resolve(f);
//   console.log('Download file: %s', f);
//   res.download(f);var file = fs.readFileSync(filePath, 'binary');
console.log('file: ', file.length);var file=filePath;var f = fs.createReadStream(file);var filename = path.basename(file);console.log('filename: ', filename);var mimetype = mime.getType(file);console.log('mimetype: ', mimetype);// res.setHeader('Content-Disposition', 'attachment; filename=' + filename);// res.setHeader('Content-Type', mimetype); //application/zip// var filestream = fs.createReadStream(file);// filestream.pipe(res)// res.writeHead(200, {//   'Content-Type': 'application/force-download',//   'Content-Disposition': 'attachment; filename=price_letter.zip'// });res.writeHead(200, {'Content-Type': "application/octet-stream",'Content-Disposition': 'attachment; filename=price_letter.gzip',//'Content-Length':352*1024,'Content-Encoding':'gzip ',//'Content-Encoding':'deflate',//gzip'Transfer-Encoding':'chunked'});f.pipe(res);
})module.exports = router 

五、所遇问题

1、
所遇问题的node版本为14.X.X,升级为16.X.X 解决了此问题

2、下载文件损坏

需了解:1、Content-Encoding值

gzip  表明实体采用GNU zip编码

compress 表明实体采用Unix的文件压缩程序

deflate  表明实体是用zlib的格式压缩的

identity  表明没有对实体进行编码。当没有Content-Encoding header时, 就默认为这种情况

gzip, compress, 以及deflate编码都是无损压缩算法,用于减少传输报文的大小,不会导致信息损失。 其中gzip通常效率最高, 使用最为广泛。
2、Content-Length

Content-Length用于描述HTTP消息实体的传输长度the transfer-length of the message-body。在HTTP协议中,消息实体长度和消息实体的传输长度是有区别,比如说gzip压缩下,消息实体长度是压缩前的长度,消息实体的传输长度是gzip压缩后的长度

3、Transfer-Encoding: chunked

注意:压缩时需要采用gzip压缩,才不会出现问题

Transfer-Encoding: chunked 表示输出的内容长度不能确定,普通的静态页面、图片之类的基本上都用不到这个。

但动态页面就有可能会用到,但我也注意到大部分asp,php,asp.net动态页面输出的时候大部分还是使用Content-Length,没有使用Transfer-Encoding: chunked。

不过如果结合:Content-Encoding: gzip 使用的时候,Transfer-Encoding: chunked还是比较有用的。

记得以前实现:Content-Encoding: gzip 输出时,先把整个压缩后的数据写到一个很大的字节数组里(如 ByteArrayOutputStream),然后得到数组大小 -> Content-Length。

如果结合Transfer-Encoding: chunked使用,就不必申请一个很大的字节数组了,可以一块一块的输出,更科学,占用资源更少。

这在http协议中也是个常见的字段,用于http传送过程的分块技术,原因是http服务器响应的报文长度经常是不可预测的,使用Content-length的实体搜捕并不是总是管用。

参考链接:nodejs提取excel中的信息填充到word文件,批量生成合同
node docx模板引擎

Nodejs做后端,实现文件压缩下载的几种方案(archiver、compressing、linux的zip命令)

NodeJS下载文件实例

transfer-encoding:chunked的含义

HTTP协议中Content-Length的详细解读

nodejs 根据excel表格和word模板,生成对应的多份word模板相关推荐

  1. 【PHP】PHP使用PHPExcel生成Excel表格文件(附带随机生成英文名函数)

    [PHP]PHP使用PHPExcel生成Excel表格文件(附带随机生成英文名函数) 前言 由于业务需要,我们需要从业务中汇总数据,并生成Excel文件. 思路是这样的 PHP要导出Excel表格文件 ...

  2. excel怎样修改表格时间和计算机一制,Excel表格中如何自动生成记录数据的日期和时间...

    前几天有人问我:Excel表格在录入信息时如何在日期单元格自动生成日期时间? 在录入表格的时候,我们经常需要录入时间,比要填写出入库时间,为了减少录入的工作量,可以把日期设置为自动生成. 例如我们在B ...

  3. 如何从Excel表格导入数据批量生成二维码

    目前二维码应用渐趋广泛,二维码具有储存量大.保密性高.追踪性高.抗损性强.备援性大.成本便宜等特性,这些特性特别适用于表单.安全保密.追踪.证照.存货盘点.资料备援等方面.那么我们怎么用条码打印软件从 ...

  4. 【csv文件转xml文件】Excel表格数据快速批量生成xml格式文件

    使用背景: 使用场景举例:数据集标签处理 有时候我们需要将固定格式的Excel表格文件(csv文件)转换为xml文件使用,例如我们在目标检测实验当中我们需要制作数据集Pascal VOC格式的标签文件 ...

  5. Excel表格中如何快速生成下拉菜单

    Excel表格中如何快速生成下拉菜单 目录 Excel表格中如何快速生成下拉菜单 1.例如下表先手动输入前几组的"等级"类别"优良中差" ​2.同时按住 alt ...

  6. python excel模板 生成excel表格_python使用xlwt生成Excel表格

    在工作中,遇到了使用python生成Excel表格的需求,经过资料的查找与对比,决定使用第三方库xlwt来生成Excel表格,现做如下总结: 简单例子: import xlwt wb = xlwt.W ...

  7. node-js——将excel表格转换成json文件

    文章目录 将excel表格转换成json文件 步骤 一.引用nodejs的xlsx模块,读取表格的数据 二.引入fs模块,创建文件并写入 三.写一个bat脚本,双击自动执行nodejs文件 示例文件下 ...

  8. python按某列拆分excel表格_Python实现将excel表格按某列拆分为多个sheet(模板格式不变)...

    #将一个excel表格,按照某列分为不同的sheet,并且将id作为sheet表格的名称 from openpyxl import load_workbook #加载需要拆分的总表个 wb = loa ...

  9. 如何从Excel表格导入数据批量生成二维码 1

    目前二维码应用渐趋广泛,二维码具有储存量大.保密性高.追踪性高.抗损性强.备援性大.成本便宜等特性,这些特性特别适用于表单.安全保密.追踪.证照.存货盘点.资料备援等方面.那么我们怎么用条码打印软件从 ...

最新文章

  1. SQL数据库的数据体系结构
  2. 网工路由基础(4)EIGRP协议
  3. tensorflow教程 学习笔记 之 Eager execution 急切执行
  4. linux常用命令(1)帮助命令man使用
  5. Object类和String类
  6. Web应用安全————Shiro 解决会话固定漏洞
  7. 测试人员眼中的问题解决策略
  8. SAE学习-使用SAE的Storage服务存储图片
  9. 文件自动备份和同步bypy和syncthing
  10. php移动文件的函数 move_uploaded_file()和copy
  11. Jsp/servlet面试题
  12. 云数据中心容灾备份方案
  13. 转:飞思卡尔单片机RAM与flash相关问题
  14. java commons math_Apache Commons Math
  15. SketchUp2020下载SketchUp2020下载安装SketchUp草图大师2020下载安装详细教程
  16. 手算KMP算法nextval数组
  17. python单位根检验平稳性怎么看是否平稳_PYthon ADF 单位根检验 如何查看结果
  18. Guge搜索引擎汇总
  19. 你知道啥是无监督聚类吗?
  20. 奥塔哥大学计算机科学怎样,奥塔哥大学自然科学学院挂科率高吗?

热门文章

  1. 深入理解 tornado 之 底层 ioloop 实现(一)
  2. 运行PHP程序时提示“Notice: Undefined index”的解决办法
  3. 网络电视盒子的选择经验
  4. 创业者必看(马云语录)
  5. intel n100核显性能 intel n100评测 n100相当于什么水平
  6. auto-extending data file /ibdata1 is of a different size 17152 pages (rounded down to MB)
  7. 喜报|九州云获评“浙江省高新技术企业研究开发中心”
  8. 运营商SDWAN组网对比之---思科Cisco-SDWAN高珊珊的博客
  9. 全新VR全景可视化制作小程序系统源码+公众号功能模块1.0.28
  10. AAA服务器搭建与实验案例