vue实现导出+ 样式修改

news2024/12/26 12:10:10
 

1.安装插件

npm install xlsx-style   ^0.18.5

npm install xlsx -S  ^0.8.13

2. 修改代码 node_modules里面找到  以下位置xlsx.js  搜索 write_ws_xml_data

替换成以下代码

function write_ws_xml_data(ws, opts, idx, wb) {
		var o = [], r = [], range = safe_decode_range(ws['!ref']), cell = "", ref, rr = "", cols = [], R = 0, C = 0, rows = ws['!rows'];
		var dense = Array.isArray(ws);
		var params = ({ r: rr }), row, height = -1;
		for (C = range.s.c; C <= range.e.c; ++C) cols[C] = encode_col(C);
		for (R = range.s.r; R <= range.e.r; ++R) {
			r = [];
			rr = encode_row(R);
			for (C = range.s.c; C <= range.e.c; ++C) {
				ref = cols[C] + rr;
				var _cell = dense ? (ws[R] || [])[C] : ws[ref];
				if (_cell === undefined) continue;
				if ((cell = write_ws_xml_cell(_cell, ref, ws, opts, idx, wb)) != null) r.push(cell);
			}
			if (r.length > 0 || (rows && rows[R])) {
				params = ({ r: rr });
				if (rows && rows[R]) {
					row = rows[R];
					if (row.hidden) params.hidden = 1;
					height = -1;
					if (row.hpx) height = px2pt(row.hpx);
					else if (row.hpt) height = row.hpt;
					if (height > -1) { params.ht = height; params.customHeight = 1; }
					if (row.level) { params.outlineLevel = row.level; }
				}
				o[o.length] = (writextag('row', r.join(""), params));
			}
		}
		if (rows) for (; R < rows.length; ++R) {
			if (rows && rows[R]) {
				params = ({ r: R + 1 });
				row = rows[R];
				if (row.hidden) params.hidden = 1;
				height = -1;
				if (row.hpx) height = px2pt(row.hpx);
				else if (row.hpt) height = row.hpt;
				if (height > -1) { params.ht = height; params.customHeight = 1; }
				if (row.level) { params.outlineLevel = row.level; }
				o[o.length] = (writextag('row', "", params));
			}
		}
		return o.join("");
	}

3.封装组件

import * as XLSX from "xlsx"
import XLSXStyle from "xlsx-style";
let _needSetStyles = []
let cols = []
let ifsubhead = false

/**
 * 导出excel表格
 * @param {Array} tableData - 需要的出表格的数组
 * @param {Array} header - 表头
 * @param {Array} headerItem - 子表
 * @param {String} notice - 注意事项
 * @param {Array} needChangeColor - 需要修改颜色的属性
 * @param {Array} clo - 每一项的宽度
 * @param {Array} subhead - 副标题信息
 * @param {string} filename - 导出文件名称
 */
export function exportData(tableData, header, headerItem, notice, needSetStyles = [], col = [], subhead = [], filename) {
    // 检查是否有需要修改颜色的属性
    _needSetStyles = needSetStyles.length > 0 ? needSetStyles : [];
    // 检查是否有指定每一列的宽度
    cols = col.length > 0 ? col : [];

    if (tableData.length > 0) {
        // 表头设置
        const aoa = [[notice]];

        console.log(tableData);
        if (subhead.length > 0) {
            aoa.push(subhead);
            ifsubhead = true
        }
        aoa.push(header);

        console.log(headerItem, 'headerItem');
        if (headerItem.length > 0) {
            headerItem.forEach(item => {
                aoa.push(item)
            })
        }

        // 创建 Excel 表格并设置样式
        const sheet = xlsxAddStyle(aoa, notice);

        // 导出文件
        openDownloadDialog(sheet2blob(sheet), `${filename}.xlsx`);
    } else {
        // 表格数据为空,可以进行相应的处理
    }

}
export function openDownloadDialog(url, saveName) {
    let urlA;
    if (typeof url === "object" && url instanceof Blob) {
        urlA = URL.createObjectURL(url); // 创建blob地址
    }
    const aLink = document.createElement("a");
    aLink.href = urlA;
    // HTML5新增的属性,指定保存文件名,可以不要后缀,注意,file:///模式下不会生效
    aLink.download = saveName || "";
    let event;
    if (window.MouseEvent) event = new MouseEvent("click");
    else {
        event = document.createEvent("MouseEvents");
        event.initMouseEvent(
            "click",
            true,
            false,
            window,
            0,
            0,
            0,
            0,
            0,
            false,
            false,
            false,
            false,
            0,
            null
        );
    }
    aLink.dispatchEvent(event);
}
// 将一个sheet转成最终的excel文件的blob对象,然后利用URL.createObjectURL下载
export function sheet2blob(sheet, sheetName) {
    var sheetNameS = sheetName || "sheet3";
    var workbook = {
        SheetNames: [sheetNameS],
        Sheets: {},
    };
    workbook.Sheets[sheetNameS] = sheet;
    workbook.Sheets['sheet100'] = sheet;
    // 生成excel的配置项
    var wopts = {
        bookType: "xlsx", // 要生成的文件类型
        bookSST: false, // 是否生成Shared String Table,官方解释是,如果开启生成速度会下降,但在低版本IOS设备上有更好的兼容性
        type: "binary",
    };
    var wbout = XLSXStyle.write(workbook, wopts);
    // XLSXStyle.write(wb, { bookType: bookType, bookSST: false, type: 'binary' });
    var blob = new Blob([s2ab(wbout)], { type: "application/octet-stream" });
    // 字符串转ArrayBuffer
    function s2ab(s) {
        var buf = new ArrayBuffer(s.length);
        var view = new Uint8Array(buf);
        for (var i = 0; i !== s.length; ++i) view[i] = s.charCodeAt(i) & 0xff;
        return buf;
    }
    return blob;
}
// 表格样式的设置
export function xlsxAddStyle(xlsx, filename) {
    // 创建工作簿
    // const workbook = XLSX.utils.book_new();
    const sheet = XLSX.utils.aoa_to_sheet(xlsx);
    console.log(sheet, 'sheet');
    const mergeArr = []; // 合并的单元格
    const rowH = []; // 表格每列高度
    // 单元格外侧有框线
    const borderAll = {
        top: { style: "thin" },
        bottom: { style: "thin" },
        left: { style: "thin" },
        right: { style: "thin" },
    };
    // 单元格外侧无框线
    const noBorder = {
        top: { style: "" },
        bottom: { style: "" },
        left: { style: "" },
        right: { style: "" },
    };

    for (const key in sheet) {
        if (Object.hasOwnProperty.call(sheet, key)) {
            const element = sheet[key];
            console.log(element, 'element');
            if (typeof element === "object") {
                const index = Number(key.slice(1)) - 1;
                rowH[index] = { hpt: 20, hpx: 20 };
                element.s = {
                    alignment: {
                        horizontal: "center", // 所有单元格右对齐
                        vertical: "center", // 所有单元格垂直居中
                    },
                    font: {
                        name: "宋体",
                        sz: 10,
                        italic: false,
                        underline: false,
                    },
                    // border: borderAll,
                    // fill: {
                    //   fgColor: { rgb: "FFFFFFFF" },
                    // },
                };
                // 指标值表格的样式
                if (key.indexOf("C") > -1) {
                    element.s.alignment.horizontal = "center";
                }
                // 标题的样式
                if (index === 1) {
                    element.s.font.bold = true;
                    element.s.rows = { hpx: 150 }
                }
                // 如果传来副标题,那么之前设置的样式会被副标题顶替掉,需要重新设置样式
                if (ifsubhead) {
                    if (index === 1) {
                        element.s.font.bold = true;
                        // 高
                        rowH[1] = { hpt: 20, hpx: 20 }
                    }
                    if (index === 2) {
                        element.s.font.bold = true;
                        rowH[2] = { hpt: 30, hpx: 30 }

                    }
                }
                // 处理合并单元格数组 s 开始 e 结束  c 列 r行
                if (element.v == filename) {
                    mergeArr.push({
                        s: { c: 0, r: 0 },
                        e: { c: cols.length - 1, r: 0 },
                    });
                    rowH[0] = { hpt: 110, hpx: 110 }

                }
                if (element.v.includes('职业工种')) {
                    mergeArr.push({
                        s: { c: 0, r: 1 },
                        e: { c: 1, r: 1 },
                    });
                }
            }
        }
    }
    // 表头的样式设置
    sheet["A1"].s.alignment.horizontal = "left";
    // sheet["A1"].s.font.underline = true;
    sheet["A1"].s.font.sz = 11;
    sheet["A1"].s.font.color = { rgb: 'FFFFFF' }
    sheet["A1"].s.border = borderAll
    sheet['A1'].s.fill = { fgColor: { rgb: '217346' } }
    // 单元格的列宽
    sheet["!cols"] = cols
    // 设置行高
    sheet['!rows'] = rowH;


    // 自定义样式
    _needSetStyles.forEach(item => {
        sheet[item.name].s = item.style
    })

    sheet["!merges"] = mergeArr;
    return sheet
}

4.页面使用

<template>
  <div>
    <el-button type="success" @click="createTemplate">导出excel</el-button>
  </div>

</template>
<script>
import {exportData} from '@/untils/exportData'  //上面组件的地址

export default {
  methods: {
    createTemplate() {
      let templateList = [{examNumber:'物质名称1',name:'物质因子1'}]
      let header = ['物质名称', '物质因子', '时间']
      let subhead = ['不存在日校准的日期请对整列进行删除;请按实际校准数据时间修改日期和小时值,若时间列不够可自行增加列;缺失数据填充-999;请勿填充非数值内容;若模板中与实际监测因子个数不一致请联系平台管理人员'];
      let notice = [
        1、xxxxxxxxxxxxxxx;
        2、xxxxxxxxxxxxxxx;
      ]
      let headerItem = templateList.map(item => {
        return [item.examNumber, item.name, '0']
      })

      const clos = [
        { wpx: 210 }, { wpx: 210 }, { wpx: 420 }
      ];
      // 字体样式
      const fontColorStyle = {
        name: "宋体",
        sz: 10,
        italic: false,
        underline: false,
        color: { rgb: 'FFFFFF' },
      };
      // 单元格外侧边框
      const borderStyle = {
        top: { style: "thin" },
        bottom: { style: "thin" },
        left: { style: "thin" },
        right: { style: "thin" },
      };

      const setStyles = [
        {
          name: 'A3',
          style: {
            font: fontColorStyle,
            fill: {
              fgColor: { rgb: 'FF4949' } // 设置背景颜色
            },
            alignment: {
              horizontal: "center", // 所有单元格右对齐
              vertical: "center", // 所有单元格垂直居中
            },
            border: borderStyle
          }
        },
        {
          name: 'B3',
          style: {
            font: fontColorStyle,
            fill: {
              fgColor: { rgb: 'FF4949' } // 设置背景颜色
            },
            alignment: {
              horizontal: "center", // 所有单元格右对齐
              vertical: "center", // 所有单元格垂直居中
            },
            border: borderStyle
          }
        },
        {
          name: 'C3',
          style: {
            font:
            fontColorStyle,
            fill: {
              fgColor: { rgb: 'FF4949' } // 设置背景颜色
            },
            alignment: {
              horizontal: "center", // 所有单元格右对齐
              vertical: "center", // 所有单元格垂直居中
            },
            border: borderStyle
          }
        }
      ]
      exportData(templateList, header, headerItem, notice, setStyles, clos, subhead, '导出模板')
    },
  },
}
</script>

就导出成功啦

ps 会报错

解决办法

 修改vue.config.js

npm install node-polyfill-webpack-plugin

const {defineConfig} = require('@vue/cli-service')

const NodePolyfillPlugin = require("node-polyfill-webpack-plugin")
module.exports = defineConfig({
    transpileDependencies: true,
    lintOnSave: false,
    parallel: false,
    productionSourceMap: false,
    chainWebpack: config => {
        //在 chainWebpack 添加下面的一段代码
        config.externals({ "./cptable": "var cptable" });
    },
    configureWebpack: {
        plugins: [
            new NodePolyfillPlugin()
        ],
        externals: {
            './cptable': 'var cptable',
            fs: require('fs')
        },
        resolve: {
            fallback: {
                fs: false
            }
        }
    },
})

如果还报错

源码中找到这个位置

搜索 var cpt = require('./cpt' + 'able'); 替换成var cpt = cptable;  解决

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

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

相关文章

Kubernetes增加master节点

一. 新增节点 无论是node节点还是master节点&#xff0c;kubelet、kubeadm、kubectl、CRI需要部署好&#xff0c; ### 新增node, 重新生成token, 复制加入即可, 前提是需要装上面的 kubectl kubeadm kubelet containerd 等 kubeadm token create --print-join-command### 新增 …

K8S对外服务ingress

Sevice作用体现在两个方面 集群内部 不断跟踪pod的变化&#xff0c;更新endpoint中的pod对象&#xff0c;基于pod的ip地址不断发现的一种服务发现机制 集群外部 类似负载均衡器&#xff0c;把流量&#xff08;ip端口&#xff09;&#xff0c;不涉及转发url&#xff08;http ht…

【Git相关问题】修改代码提交push时的用户名字

最简方法如下&#xff1a; 直接修改Git的用户配置文件 .gitconfig&#xff0c;这个配置文件的路径一般是 C:\Users\本机用户名\.gitconfig 用记事本或编辑器打开&#xff0c;在[user]下即可修改用户名name或邮箱email 参考&#xff1a; 使用Git进行版本控制&#xff0c;不同…

动态住宅代理IP是什么?如何配置使用?

动态住宅代理IP&#xff0c;作为一种高效的网络工具&#xff0c;不仅能够为您的在线活动提供额外的保护层&#xff0c;还能增强匿名性和数据安全。接下来将深入探讨动态住宅代理IP的定义、设置步骤、以及它如何有效保护您的网络隐私和安全。 一、动态住宅代理是什么&#xff1f…

YOLOv8在NX上的tensorrt的加速部署(60帧率)

所需环境 所有过程均可以参考本人所写的文章 (1)虚拟环境工具 MInforge3-Linux-aarch64 Jetson 平台都是RAM架构,平常的conda都是基于X86架构平台的。环境搭建参考文章 (2)YOLOv8_ros代码,采用自己创建的yolov_ros代码。yolov8_ros参考文章 (3)jetpack 环境(本篇文章…

openssl3.2 - 官方demo学习 - test - certs

文章目录 openssl3.2 - 官方demo学习 - test - certs概述笔记.sh的执行语句打印的方法要修改的实际函数END openssl3.2 - 官方demo学习 - test - certs 概述 官方demos目录有证书操作的例子 已经做了笔记 openssl3.2 - 官方demo学习 - certs 但是这个demos/certs目录的脚本,…

el-date-picker默认结束为当前时分秒

在element ui中的日期时间选择组件中默认是00:00,现在需求是点击默认结束时间为当前时分秒&#xff0c;查了很多资料写的都不准确 需求&#xff1a;实现日期时间组件可选择当前日期&#xff0c;比如当前是2024年01月17号下午17&#xff1a;21 那选中时必须结束时间为17&#x…

zabbix实验

目录 一、zabbix 自动发现与自动注册 1、zabbix 自动发现 ①关闭防火墙和安全机制 ②在服务端和客户端上配置 hosts 解析 ③在 Web 页面配置自动发现 2、zabbix 自动注册 ①环境准备 ②在服务端和客户端上配置 hosts 解析 ③修改 zabbix-agent2 配置文件 ④在 Web 页…

TDengine 企业级功能:存储引擎对多表低频场景优化工作分享

在去年 8 月份发布的 3.1.0.0 版本中&#xff0c;TDengine 进行了一系列重要的企业级功能更新&#xff0c;其中包括对多表低频场景写入性能的大幅优化。这一优化工作为有此需求的用户提供了更大的便捷性和易用性。在本文中&#xff0c;TDengine 的资深研发将对此次优化工作进行…

什么是线程(多线程),Python多线程的好处

几乎所有的操作系统都支持同时运行多个任务&#xff0c;一个任务通常就是一个程序&#xff0c;每一个运行中的程序就是一个进程。当一个程序运行时&#xff0c;内部可能包含多个顺序执行流&#xff0c;每一个顺序执行流就是一个线程。 线程和进程 几乎所有的操作系统都支持进…

【Dynamo学习笔记】Dynamo for Revit建模基础

目录 前言1 Revit模型的结构2 图元的操作2.1 图元的选择2.2 图元参数的读取和写入2.3 图元的创建2.3.2 创建轴网2.3.2 创建结构柱2.3.3 创建结构框架2.3.4 创建墙体 3 自定义节点 参考资料&#xff1a; &#xff08;1&#xff09; 罗嘉祥&#xff0c;宋姗&#xff0c;田宏钧. 《…

组态王软件安装教程6.51/6.53/5.55/6.60/7.5SP2版本组态软件

组态王软件是一款功能强大的工业自动化软件&#xff0c;以下是各个版本的主要特点&#xff1a; 组态王6.51&#xff1a;该版本是亚控科技在组态王6.0x系列版本成功应用后&#xff0c;广泛征询数千家用户的需求和使用经验&#xff0c;采取先进软件开发模式和流程&#xff0c;由…

c语言字符串追加

系列文章目录 c语言字符串追加 c语言字符串追加 系列文章目录c语言字符串追加 c语言字符串追加 int main() {char arr1[] "hello";char arr2[] "world";char arrbuf[100] { 0 };//全部初始化\0int index 0;while (arr1[index]! \0){//1、将非\0的字符添…

基于springboot+vue的网上订餐系统(前后端分离)

博主主页&#xff1a;猫头鹰源码 博主简介&#xff1a;Java领域优质创作者、CSDN博客专家、公司架构师、全网粉丝5万、专注Java技术领域和毕业设计项目实战 主要内容&#xff1a;毕业设计(Javaweb项目|小程序等)、简历模板、学习资料、面试题库、技术咨询 文末联系获取 项目背景…

机器视觉检测设备在连接器外观缺陷检测中的应用

作为传输电流或信号连接两个有源器件的器件&#xff0c;连接器被广泛应用于各个行业&#xff0c;从手机、平板、电脑&#xff0c;到冰箱、空调、洗衣机&#xff0c;再到汽车、国防、航空&#xff0c;处处是它的所在。每个电子产品少了连接器将无法运作&#xff0c;因此&#xf…

JRT和springboot比较测试

想要战胜他&#xff0c;必先理解他。这两天系统的学习Maven和跑springboot工程&#xff0c;从以前只是看着复杂到亲手体验一下&#xff0c;亲自实践的才是更可靠的了解。 第一就是首先Maven侵入代码结构&#xff0c;代码一般要按约定搞src/main/java。如果是能严格执行测试的项…

竞赛保研 大数据房价预测分析与可视

0 前言 &#x1f525; 优质竞赛项目系列&#xff0c;今天要分享的是 &#x1f6a9; 大数据房价预测分析与可视 &#x1f947;学长这里给一个题目综合评分(每项满分5分) 难度系数&#xff1a;3分工作量&#xff1a;3分创新点&#xff1a;4分 该项目较为新颖&#xff0c;适合…

如何保证HUAWEI交换机成功使用ssh登录?

1&#xff09;telnet 部分配置4行 telnet server enable telnet server-source all-interface local-user admin service-type telnet ssh stelnet server enable 2&#xff09;ssh local-user admin service-type telnet ssh ssh server-source all-interface ssh server c…

Windows pip install -r requirements.txt 太慢

目录 解决方案一&#xff1a; 解决方案二&#xff1a; 下载单个包时切换源&#xff1a; 解决方案一&#xff1a; 1、在虚拟环境中切换下载的源&#xff1a; pip config set global.index-url https://pypi.tuna.tsinghua.edu.cn/simple 2、当出现有pip.txt文件写入时&…

解决springboot启动报Failed to start bean ‘subProtocolWebSocketHandler‘;

解决springboot启动报 Failed to start bean subProtocolWebSocketHandler; nested exception is java.lang.IllegalArgumentException: No handlers 问题发现问题解决 问题发现 使用springboot整合websocket&#xff0c;启动时报错&#xff0c;示例代码&#xff1a; EnableW…