前端导出word文件的多种方式、前端导出excel文件

news2024/9/25 21:29:42

文章目录

  • 纯前借助word模板端导出word文件 (推荐)
    • 使用模板导出
  • 前端通过模板字符串导出word文件
  • 前端导出 excel文件,node-xlsx导出文件,行列合并

纯前借助word模板端导出word文件 (推荐)

先看效果:
这是页面中的table
在这里插入图片描述
这是导出后的效果:
在这里插入图片描述

使用模板导出

需要的依赖:
npm 自行安装,需要看官网的具体参数自行去github上面找对应的参数

 	"docxtemplater": "^3.46.0",
    "pizzip": "^3.1.6",
    "jszip-utils": "^0.1.0",
    "file-saver": "^2.0.5",

具体代码:(先看word模板,在看代码,word中的变量和代码中 doc.setData() 是一一对应的)
在这里插入图片描述

<template>
  <div class="button-box">
    <a-space>
      <a-button type="danger" @click="downWord2">模板导出word文件</a-button>
    </a-space>
  </div>
</template>

<script lang="ts">
import { defineComponent, onMounted, reactive, PropType, ref } from 'vue';
import { message } from 'ant-design-vue';
import moment from 'moment';
import { downloadPDF } from '../../../../utils/utils';
import { useTable } from './hooks/useTable';
import xlsx from 'node-xlsx';

import docxtemplater from 'docxtemplater';
import PizZip from 'pizzip';
import JSZipUtils from 'jszip-utils';
import { saveAs } from 'file-saver';

export default defineComponent({
  props: {
    /**
     * 基础数据
     */
    baseData: {
      type: Object as PropType<{
        taskId: string;
        barcodeId: string;
      }>,
      default: {},
    },
    /**
     * 样本名称
     */
    barcodeName: {
      type: String,
    },
  },

  setup(props) {
    let width = 100;
    const { barcodeName } = props;
    const { taskId, barcodeId } = props.baseData;
    const { tableConfig, tableConfigLeft, getDta } = useTable();



    onMounted(() => {
      barcodeName ? getDta(taskId, barcodeName) : '';
    });
    
    const tableValue = reactive({
      unit: '中国',
      date: undefined,
      sampleType: '你猜',
      people: '黄种人',
      name: '夜空',
      sex: '男',
      age: '25',
      work: '开发',
      id: '',
      jiance: '商品化试剂盒',
      date2: undefined,
    });

   
    const downWord2 = () => {
      let docxname = '导出word.docx';
      JSZipUtils.getBinaryContent('/test.docx', function (error: any, content: any) {
        // test.docx是模板(这里我放到public公共文件夹下面了)。我们在导出的时候,会根据此模板来导出对应的数据
        // 抛出异常
        if (error) {
          throw error;
        }

        // 创建一个PizZip实例,内容为模板的内容
        let zip = new PizZip(content);
        // 创建并加载docx templater实例对象
        let doc = new docxtemplater().loadZip(zip);
        // 设置模板变量的值  主要变量替换在这里
        doc.setData({
          name: tableValue.name,
          unit: tableValue.unit,
          date: moment(tableValue.date).format('YYYY-MM-DD'),
          sampleType: tableValue.sampleType,
          sex: tableValue.sex,
          age: tableValue.age,
        });

        try {
          // 用模板变量的值替换所有模板变量
          doc.render();
        } catch (error: any) {
          // 抛出异常
          let e = {
            message: error.message,
            name: error.name,
            stack: error.stack,
            properties: error.properties,
          };
          console.log(
            JSON.stringify({
              error: e,
            }),
          );
          throw error;
        }

        // 生成一个代表docxtemplater对象的zip文件(不是一个真实的文件,而是在内存中的表示)
        let out = doc.getZip().generate({
          type: 'blob',
          mimeType: 'application/vnd.openxmlformats-officedocument.wordprocessingml.document',
        });
        // 将目标文件对象保存为目标类型的文件,并命名
        saveAs(out, docxname);
      });
    };

    return {
      downWord2,
      getDta,
      tableConfig,
      tableConfigLeft,
      tableValue,
      downloadPDF,
      value4: ref('less'),
    };
  },
});
</script>

<style lang="less" scoped>

</style>

前端通过模板字符串导出word文件

包依赖:

 "file-saver": "^2.0.5",

代码

import FileSaver from 'file-saver';
import htmlDocx from "html-docx-js/dist/html-docx"
import { G } from '@/global';
const { rootUrl, rbacToken } = G;
let cycle_info1 = [
  {
    name: '事件类型',
    key: 'eventTypeName',
  },
  {
    name: '地点定位',
    key: 'locationAddress',
  },
  {
    name: '上报时间',
    key: 'reportTime',
  },
  {
    name: '人员姓名',
    key: 'reportUserName',
  },
  {
    name: '联系方式',
    key: 'reportUserPhone',
  },
]

const model = (reportInfoDetail: any, list: any, eventState: any) => {
  // console.log(reportInfoDetail, list, eventState);

  return (
    `
    <!DOCTYPE html>
      <html>

<head>
  <style>
    .MaxBox {
      padding: 0px 15px;
      overflow-y: auto;
      height: 50vh;
    }

    .fromBox {}

    .formTitle_first {
      color: #1c69f7;
      font-size: 23px;
      font-weight: bold;
      margin-bottom: 10px;
    }

    .formTitle_second {
      font-weight: bold;
      font-size: 16px;
      margin-bottom: 10px;
    }

    .formContent_box {
      margin-bottom: 5px;
    }

    .formContent_box_title {
      min-width: 60px;
    }

    .display_flex {
      display: flex;
    }
  </style>
</head>

<body>
  <div class="MaxBox">
    <div class="fromBox">
      <div class="formTitle_first">上报信息</div>
      <div class="formTitle_second">上报信息</div>
      <div class="formContent_box display_flex" style="display:flex">
        <span class="formContent_box_title" >事件类型:</span>
        <span>${reportInfoDetail['eventTypeName']}</span>
      </div>
      <div class="formContent_box display_flex" style="display:flex">
        <span class="formContent_box_title">地点定位:</span>
        <span>${reportInfoDetail['locationAddress']}</span>
      </div>
      <div class="formContent_box display_flex" style="display:flex">
        <span class="formContent_box_title">上报时间:</span>
        <span>${reportInfoDetail['reportTime']}</span>
      </div>
      <div class="formContent_box display_flex" style="display:flex">
        <span class="formContent_box_title">人员姓名:</span>
        <span>${reportInfoDetail['reportUserName']}</span>
      </div>
      <div class="formContent_box display_flex" style="display:flex">
        <span class="formContent_box_title">联系方式:</span>
        <span>${reportInfoDetail['reportUserPhone']}</span>
      </div>
    
      <div class="formTitle_second">图片附件</div>
      <div class="formContent_box">
        ${reportInfoDetail['picIds']?.map((res1: any, idx1: any) => {
      return `
        <img width='240' height='160' src="${rootUrl}/fyVolunteer/file/download/${res1}?rbacToken=${rbacToken}"
          style='margin-right:5px'
        />
        ${((idx1 + 1) % 2 == 0) ? `<br />` : ''}
        `
    })
    }
      </div>
      <div class="formTitle_second">事件描述</div>
      <div class="formContent_box">${reportInfoDetail['description']}</div>
    </div>
    ${reportInfoDetail.assignInfo.length != 0 ?
      `
      <div class="fromBox">
      <div class="formTitle_first">指派信息</div>
      <div class="formTitle_second  display_flex">指派信息</div>
      <div class="formContent_box">
        <div class="formContent_box_title">指派单位:
          ${reportInfoDetail.assignInfo.map((res: any, idx: any) => {
        return `
              <span style="margin-right:15px">
                ${res.departmentName}
              </span>
              `
      })
      }
        </div >
      </div >
      <div class="formContent_box  display_flex">
          <span class="formContent_box_title">指派时间:</span>
          <span>${!!reportInfoDetail?.assignInfo[0]?.assignTime ? reportInfoDetail?.assignInfo[0]?.assignTime : ""}</span>
      </div>
    </div>
      `: ''

    }  

    <div class="fromBox">
      <div class="formTitle_first">处置信息</div>
      ${reportInfoDetail.handleInfo.length != 0 ?
      reportInfoDetail.handleInfo.map((itm: any, idx: any) => {
        return `
        <div class="formTitle_second">单位${idx + 1}${itm['claimDepartmentName']}</div>
        <div class="formTitle_second">签收信息</div>
        <div class="formContent_box display_flex"
        style="width:32vw;justify-content: space-between;">
          <div>
            <span>签收单位:${itm['claimDepartmentName']}</span>
          </div>
          <div>
            <span>签收时间:${itm['claimTime']}</span>
          </div>
        </div >
        <div class="formTitle_second">图片附件</div>
        <div class="formContent_box">
          ${itm['handleTime'] != null ?
            itm['handlePicIds']?.map((res1: any, idx1: any) => {
              return `
          <img width="240" height="160"
            src="${rootUrl}/fyVolunteer/file/download/${res1}?rbacToken=${rbacToken}"
            style="margin-right:5px"
          />
          ${(idx1 + 1) % 2 == 0 ? `<br />` : ''}
          `
            }) : `<span style="color:#5558e8">无</span>`
          }
        </div>

        <div class="formTitle_second">处置描述</div>
        <div class="formContent_box">${itm.handleTime != null ? itm['handleDescription'] : `<span style="color:#5558e8">未上传处置</span>`}</div>

        <div class="formTitle_second">上报信息</div>
        <div class="formContent_box display_flex"
        style="width:32vw;justify-content: space-between;">
          <div>
            <span>上报单位:${itm['claimDepartmentName']}</span>
          </div>
          <div>
            <span>上报时间:${itm['handleTime'] != null ? itm['handleTime'] : ''}</span>
          </div>
        </div>
        <br/>
        `
      }) : '无数据'
    }
    </div >

    <div class="fromBox">
      <div class="formTitle_first">其他信息</div>

      <div class="formContent_box  display_flex">
        <span class="formContent_box_title">信息状态:</span>
        <span>
          ${list[eventState - 1].desc}
          ${reportInfoDetail?.finishTime != null ? reportInfoDetail?.finishTime : ''}
        </span>
    </div>
    <div class="formContent_box  display_flex">
      <span class="formContent_box_title">采纳状态:</span>
      <span>${reportInfoDetail.acceptInfo == null ? "未采纳" : `已采纳(${reportInfoDetail.acceptInfo.integral})`}</span>
    </div>
  </div>
  </div >
</body >
</html >
  `
  )
}

const loadFile = (info: any) => {
  let html = model(info.reportInfoDetail, info.list, info.eventState)
  let blob = new Blob([html], { type: "application/msword;charset=utf-8" });
  // let blob = htmlDocx.asBlob(html, { orientation: "landscape" });
  FileSaver.saveAs(blob, "信息管理文件.doc");
}


export {
  loadFile
};



前端导出 excel文件,node-xlsx导出文件,行列合并

导出效果:
在这里插入图片描述

需要的依赖: node-xlsx

    "node-xlsx": "^0.23.0",

代码:

    const downXlsx = () => {
      let data = [
        [1, 222, '', '', '', ''],
        ['', 2, 3, 4, 5, 6],
        ['', 2, 3, 4, 5, 6],
        ['', 2, 3, 4, 5, 6],
        ['', 2, 3, 4, 5, 6],
        [22, 2, 3, 4, 5, 6],
      ];

      // 行列合并规则  c:col 列   r:row 行
      const range0 = { s: { c: 0, r: 0 }, e: { c: 0, r: 4 } };
      const range1 = { s: { c: 1, r: 0 }, e: { c: 5, r: 0 } };
      const sheetOptions = {
        '!merges': [range0, range1],
        // cols 列宽大小
        '!cols': [{ wch: 5 }, { wch: 10 }, { wch: 15 }, { wch: 20 }, { wch: 30 }, { wch: 50 }],
      };
      //如果不需要格式,这里的sheetOptions可以省略不写
      let result = xlsx.build([{ name: 'sheet1', data }], { sheetOptions });
      const ab = Buffer.from(result, 'binary');
      const blob = new Blob([ab]);
      const blobUrl = URL.createObjectURL(blob);
      const a = document.createElement('a');
      a.href = blobUrl;
      a.download = '导出excel.xlsx';
      a.click();
      window.URL.revokeObjectURL(blobUrl);
    };

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

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

相关文章

官封弼马心何足,名注齐天意未宁

解法一&#xff1a; 设left为多&#xff0c;right为少 每次分裂满足; 所以; 定义函数num(n,k)&#xff0c;子问题为num(l,k&#xff09;和num(r,k)。 递归结束&#xff1a;不可以精确分裂 #include<iostream> #include<vector> #include<algorithm> us…

24款奔驰C260L升级原厂360全景影像 高清环绕的视野

360全景影像影像系统提升行车时的便利&#xff0c;不管是新手或是老司机都将是一个不错的配置&#xff0c;无论是在倒车&#xff0c;挪车以及拐弯转角的时候都能及时关注车辆所处的环境状况&#xff0c;避免盲区事故发生&#xff0c;提升行车出入安全性。星骏汇小许Xjh15863 3…

计算机网络——22TCP拥塞

TCP拥塞 TCP拥塞控制机制 端到端的拥塞控制机制 路由器不向主机有关拥塞的反馈信息 路由器的负担较轻符合网络核心简单的TCP/IP架构原则 端系统根据自身得到的信息&#xff0c;判断是否发生拥塞&#xff0c;从而采取动作 拥塞控制的几个问题 如何检测拥塞 轻微拥塞拥塞 控…

项目解决方案:社会视频资源接入平台解决方案

目 录 一、项目背景 二、方案简述 1、监控功能 2、视频录像 三、系统构架 四、产品功能及特点 1、实时图像点播 2. 远程控制 3. 存储和备份 4. 历史图像的检索和回放 5、报警管理 &#xff08;1&#xff09;报警配置 &#xff08;2&#xff09;报警的…

Linux中systemv共享内存

目录 1.原理 2.接口 1.shmget(share_memory_get获得共享内存) 2.ftok 3.shmat(share_memory_attaintion挂接到物理内存上) 4.key和shmid的区别 5.ipc 指令 6.shmdt函数&#xff08;share_memory_detach取消挂接&#xff09; 7.shmctl函数&#xff08;share_memory_cont…

Dell R730 2U服务器实践3:安装英伟达上代专业AI训练Nvidia P4计算卡

Dell R730是一款非常流行的服务器&#xff0c;2U的机箱可以放入两张显卡&#xff0c;这次先用一张英伟达上代专业级AI训练卡&#xff1a;P4卡做实验&#xff0c;本文记录安装过程。 简洁步骤&#xff1a; 打开机箱将P4显卡插在4号槽位关闭机箱安装驱动 详细步骤&#xff1a; 对…

Ubuntu服务器fail2ban的使用

作用&#xff1a;限制ssh远程登录&#xff0c;防止被人爆破服务器&#xff0c;封禁登录ip 使用lastb命令可查看到登录失败的用户及ip&#xff0c;无时无刻的不在爆破服务器 目录 一、安装fail2ban 二&#xff0c;配置fail2ban封禁ip的规则 1&#xff0c;进入目录并创建ssh…

STL容器之string类

文章目录 STL容器之string类1、 什么是STL2、STL的六大组件3、string类3.1、string类介绍3.2、string类的常用接口说明3.2.1、string类对象的常见构造3.2.2、string类对象的容量操作3.2.3、string类对象的访问及遍历操作3.2.4、 string类对象的修改操作3.2.5、 string类非成员函…

在线上传解压PHP文件代码,压缩/压缩(网站一键打包)支持密码登录

在线上传解压PHP文件代码&#xff0c;压缩/压缩(网站一键打包)支持密码登录 资源宝分享&#xff1a;www.httple.net 如果你没有主机控制面板这个是最好选择&#xff0c;不需要数据库&#xff0c;上传当控制面板使用&#xff0c;无需安装任何扩展&#xff0c;安全高&#xff0c;…

算法刷题day20:二分系列

目录 引言一、借教室二、分巧克力三、管道四、技能升级五、冶炼金属六、数的范围七、最佳牛围栏 引言 这几天一直在做二分的题&#xff0c;都是上了难度的题目&#xff0c;本来以为自己的二分水平已经非常熟悉了&#xff0c;没想到还是糊涂了一两天才重新想清楚&#xff0c;想…

Redis主从复制+Redis哨兵模式+Redis群集模式

Redis主从复制Redis哨兵模式Redis群集模式一、Redis主从复制1、主从复制的作用2、主从复制过程3、搭建Redis主从复制3.1 所有节点服务器安装redis3.2 修改Redis配置文件(Master节点操作)3.3 修改Redis配置文件(Slave节点操作)3.4 验证主从效果 二、Redis哨兵模式1、哨兵模式的作…

2024最详细的接口测试用例设计教程

一、接口测试流程 1、需求讨论 2、需求评审 3、场景设计 4、数据准备 5、测试执行 二、分析接口文档元素 1、接口名称 2、接口地址 3、支持格式 4、请求方式 5、请求参数&#xff08;参数名称、类型、是否必填、参数说明等&#xff09; 6、返回参数&#xff08;返回…

博途PLC 面向对象系列之“双通气缸功能块“(SCL代码)

1、面向对象系列之找对象 https://rxxw-control.blog.csdn.net/article/details/136150027https://rxxw-control.blog.csdn.net/article/details/1361500272、博途PLC 面向对象系列之"单通气缸功能块" https://rxxw-control.blog.csdn.net/article/details/1363399…

DB-GPT:大模型 + 数据库,全流程自动化

DB-GPT&#xff1a;大模型 数据库&#xff0c;全流程自动化 提出背景DB-GPT 结构具体问题与解法背景分析对比其他工具DB-GPT系统设计 提出背景 论文&#xff1a;https://arxiv.org/pdf/2312.17449.pdf 代码&#xff1a;https://github.com/eosphoros-ai/DB-GPT 本文介绍了D…

pytorch --反向传播和优化器

1. 反向传播 计算当前张量的梯度 Tensor.backward(gradientNone, retain_graphNone, create_graphFalse, inputsNone)计算当前张量相对于图中叶子节点的梯度。 使用反向传播&#xff0c;每个节点的梯度&#xff0c;根据梯度进行参数优化&#xff0c;最后使得损失最小化 代码…

Dynamo幕墙探究系列(一)

一直想写个系列教程&#xff0c;但是没有那么多时间整理资料&#xff0c;这次呢&#xff0c;先弄个小系列吧&#xff0c;还是和之前差不多的幕墙测试&#xff0c;我们分几节课&#xff0c;一步一步深入研究。 今天先开个小头儿&#xff0c;要弄的&#xff0c;就是下面这么个模型…

小程序图形:echarts-weixin 入门使用

去官网下载整个项目&#xff1a; https://github.com/ecomfe/echarts-for-weixin 拷贝ec-canvs文件夹到小程序里面 index.js里面的写法 import * as echarts from "../../components/ec-canvas/echarts" const app getApp(); function initChart(canvas, width, h…

【IDEA】2023版IDEA安装破解教程

2023版IDEA安装破解教程 第一步&#xff1a;IDEA的卸载 这里以Windows11系统为例&#xff0c;首先我们打开控制面板&#xff0c;点击程序&#xff0c;找到自己的IDEA&#xff0c;双击卸载。&#xff08;或者可以直接找到idea所在文件位置&#xff0c;直接delete文件夹&#x…

化肥工业5G智能制造工厂数字孪生可视化平台,推进化肥行业数字化转型

化肥工业5G智能制造工厂数字孪生可视化平台&#xff0c;推进化肥行业数字化转型。随着科技的不断发展&#xff0c;数字化转型已经成为各行各业发展的必然趋势。在化肥工业领域&#xff0c;5G智能制造工厂数字孪生可视化平台的应用正在逐渐普及&#xff0c;为行业数字化转型提供…

微信小程序云开发教程——墨刀原型工具入门(页面交互+交互案例教程)

引言 作为一个小白&#xff0c;小北要怎么在短时间内快速学会微信小程序原型设计&#xff1f; “时间紧&#xff0c;任务重”&#xff0c;这意味着学习时必须把握微信小程序原型设计中的重点、难点&#xff0c;而非面面俱到。 要在短时间内理解、掌握一个工具的使用&#xf…