vue3 + antd vue 纯前端 基于xlsx 实现导入excel 转 json,将json数据转换XLSX导出(模版下载)

一、导入

0、关键代码

// 安装插件
npm i xlsx/yarn add xlsx
// 导入xlsx
import * as XLSX from 'xlsx';

点击提交的时候才整理数据。上传的时候文件保存在  state.form.file[0] 中的

// 定义字段映射关系
const fieldMap = {sheet2json: {技能名称: 'skill_name',技能等级: 'skill_level',技能描述: 'skill_desc',技能类型: 'skill_type',技能效果: 'skill_effect',技能消耗: 'skill_cost',技能持续时间: 'skill_duration',技能范围: 'skill_range',技能范围: 'skill_range',技能目标: 'skill_target'}
};// 提交 --- 点击提交的时候才整理数据。上传的时候文件保存的  state.form.file[0] 中的
const handleSummit = () => {formRef.value.validate().then(async () => {try {const data = await state.form.file[0].arrayBuffer(); // 使用 arrayBuffer 避免中文乱码const workbook = XLSX.read(data, { type: 'buffer' });const outdata = XLSX.utils.sheet_to_json(workbook.Sheets[workbook.SheetNames[0]]);// 映射字段名并过滤掉不符合预期的数据const mappedData = outdata.map(row => {return Object.keys(row).reduce((targetMap, key) => {const mappedKey = fieldMap.sheet2json[key];if (mappedKey) {targetMap[mappedKey] = row[key];}return targetMap;}, {});}).filter(item => Object.keys(item).length > 0); // 过滤空对象console.log('------- 导入的数据 -------', mappedData);emits('submit', mappedData);handleClose();} catch (error) {}});
};

1、template

<a-form :model="state.form" name="form" ref="formRef" :label-col="{ style: { width: '120px' } }" autocomplete="off" :rules="rules"><a-form-item label="导入文件上传" name="file" :rules="rules.file"><div class="file-warp" style="position: relative"><a-uploadstyle="margin-left: 20px":file-list="state.form.file"name="file":customRequest="upload":beforeUpload="beforeUpload"@remove="handleRemove"accept=".xlsx, .xls"><a-button type="primary"><upload-outlined></upload-outlined>上传文件</a-button></a-upload><a-button type="primary" ghost style="position: absolute; top: 0; left: 150px" @click="handleDownload"><VerticalAlignBottomOutlined></VerticalAlignBottomOutlined>模版下载</a-button></div></a-form-item>
</a-form>

2、script

import * as XLSX from 'xlsx';
import { reactive, ref } from 'vue';const state = reactive({form: {file: []}
});
const formRef = ref(null);
const open = ref(true);const rules = {file: [{ required: true, message: '请选择文件', trigger: ['blur', 'change'] }]
};// 定义字段映射关系
const fieldMap = {sheet2json: {技能名称: 'skill_name',技能等级: 'skill_level',技能描述: 'skill_desc',技能类型: 'skill_type',技能效果: 'skill_effect',技能消耗: 'skill_cost',技能持续时间: 'skill_duration',技能范围: 'skill_range',技能范围: 'skill_range',技能目标: 'skill_target'},json2sheet: {skill_name: '技能名称',skill_level: '技能等级',skill_desc: '技能描述',skill_type: '技能类型',skill_effect: '技能效果',skill_cost: '技能消耗',skill_duration: '技能持续时间',skill_range: '技能范围',skill_target: '技能目标'}
};// 上传文件之前检测
const beforeUpload = file => {const isXlsxOrXls = file.name.split('.')[1] == 'xlsx' || file.name.split('.')[1] == 'xls';if (!isXlsxOrXls) {message.error('只允许上传xlsx, xls格式的文件!');return false;}const isLt10M = file.size / 1024 / 1024 < 10;if (!isLt10M) {message.error('文件不得大于10MB!');return false;}return isXlsxOrXls && isLt10M;
};// 选择文件
const upload = file => {// 原本调用接口上传的// uplaodFile(file.file).then(res => {//   fileList.value.push({ name: res.data.originalFilename, url: viteConfig.baseUrl + res.data.fileName, fileUrl: res.data.fileName });//   formRef.value.clearValidate();// });state.form.file = [file.file];formRef.value.clearValidate();
};// 移除文件
const handleRemove = file => {state.form.file = [];
};// 提交 转换数据
const handleSummit = () => {formRef.value.validate().then(async () => {try {const data = await state.form.file[0].arrayBuffer(); // 使用 arrayBuffer 避免中文乱码const workbook = XLSX.read(data, { type: 'buffer' });const outdata = XLSX.utils.sheet_to_json(workbook.Sheets[workbook.SheetNames[0]]);// 映射字段名并过滤掉不符合预期的数据const mappedData = outdata.map(row => {return Object.keys(row).reduce((targetMap, key) => {const mappedKey = fieldMap.sheet2json[key];if (mappedKey) {targetMap[mappedKey] = row[key];}return targetMap;}, {});}).filter(item => Object.keys(item).length > 0); // 过滤空对象console.log('------- 导入的数据 -------', mappedData);emits('submit', mappedData);handleClose();} catch (error) {}});
};

二、模板下载

1、script

// 定义字段映射关系
const fieldMap = {json2sheet: {skill_name: '技能名称',skill_level: '技能等级',skill_desc: '技能描述',skill_type: '技能类型',skill_effect: '技能效果',skill_cost: '技能消耗',skill_duration: '技能持续时间',skill_range: '技能范围',skill_target: '技能目标'}
};// 模板数据
let templateData = [{skill_name: '大刀斩',skill_level: '5',skill_desc: '技能描述',skill_type: '大招',skill_effect: '亚瑟王那样的大招',skill_cost: '10000',skill_duration: '10',skill_range: '500',skill_target: '目标:亚瑟王'}
];// 模版下载
const handleDownload = () => {// 映射字段名并过滤掉不符合预期的数据const list = templateData.map(row => {return Object.keys(row).reduce((targetMap, key) => {const mappedKey = fieldMap.json2sheet[key];if (mappedKey) {targetMap[mappedKey] = row[key];}return targetMap;}, {});}).filter(item => Object.keys(item).length > 0); // 过滤空对象;const workSheet = XLSX.utils.json_to_sheet(list);const workBook = XLSX.utils.book_new();XLSX.utils.book_append_sheet(workBook, workSheet, '技能表');// 生成Excel文件并下载XLSX.writeFile(workBook, '技能表模板.xlsx');
};

三、完整的文件

<!--* @Description: ------------ fileDescription -----------* @Author: snows_l snows_l@163.com* @Date: 2024-07-18 14:46:47* @LastEditors: snows_l snows_l@163.com* @LastEditTime: 2024-07-19 15:51:19* @FilePath: /digital-qiankun-you/cmdb/src/pages/ipSource/components/uploadFile.vue
-->
<template><div class="upeate-field-warp"><a-modal width="800px" v-model:open="open" :z-index="10004" centered :title="'规划导入'"><template #footer><a-button type="primary" @click="handleSummit">确认</a-button></template><div class="update-field-content-warp"><a-form :model="state.form" name="form" ref="formRef" :label-col="{ style: { width: '120px' } }" autocomplete="off" :rules="rules"><a-form-item label="导入文件上传" name="file" :rules="rules.file"><div class="file-warp" style="position: relative"><a-uploadstyle="margin-left: 20px":file-list="state.form.file"name="file":customRequest="upload":beforeUpload="beforeUpload"@remove="handleRemove"accept=".xlsx, .xls"><a-button type="primary"><upload-outlined></upload-outlined>上传文件</a-button></a-upload><a-button type="primary" ghost style="position: absolute; top: 0; left: 150px" @click="handleDownload"><VerticalAlignBottomOutlined></VerticalAlignBottomOutlined>模版下载</a-button></div></a-form-item></a-form></div></a-modal></div>
</template><script setup>
import { UploadOutlined, VerticalAlignBottomOutlined } from '@ant-design/icons-vue';
import { reactive, ref } from 'vue';
import * as XLSX from 'xlsx';const emits = defineEmits(['submit']);const state = reactive({form: {file: []}
});
const formRef = ref(null);
const open = ref(true);const rules = {file: [{ required: true, message: '请选择文件', trigger: ['blur', 'change'] }]
};// 上传文件之前检测
const beforeUpload = file => {const isXlsxOrXls = file.name.split('.')[1] == 'xlsx' || file.name.split('.')[1] == 'xls';if (!isXlsxOrXls) {message.error('只允许上传xlsx, xls格式的文件!');return false;}const isLt10M = file.size / 1024 / 1024 < 10;if (!isLt10M) {message.error('文件不得大于10MB!');return false;}return isXlsxOrXls && isLt10M;
};// 选择文件
const upload = file => {// 原本调用接口上传的// uplaodFile(file.file).then(res => {//   fileList.value.push({ name: res.data.originalFilename, url: viteConfig.baseUrl + res.data.fileName, fileUrl: res.data.fileName });//   formRef.value.clearValidate();// });state.form.file = [file.file];formRef.value.clearValidate();
};// 移除文件
const handleRemove = file => {state.form.file = [];
};// 初始化
const init = () => {open.value = true;
};// 关闭
const handleClose = () => {open.value = false;
};// 定义字段映射关系
const fieldMap = {sheet2json: {技能名称: 'skill_name',技能等级: 'skill_level',技能描述: 'skill_desc',技能类型: 'skill_type',技能效果: 'skill_effect',技能消耗: 'skill_cost',技能持续时间: 'skill_duration',技能范围: 'skill_range',技能范围: 'skill_range',技能目标: 'skill_target'},json2sheet: {skill_name: '技能名称',skill_level: '技能等级',skill_desc: '技能描述',skill_type: '技能类型',skill_effect: '技能效果',skill_cost: '技能消耗',skill_duration: '技能持续时间',skill_range: '技能范围',skill_target: '技能目标'}
};// 模板数据
let templateData = [{skill_name: '大刀斩',skill_level: '5',skill_desc: '技能描述',skill_type: '大招',skill_effect: '亚瑟王那样的大招',skill_cost: '10000',skill_duration: '10',skill_range: '500',skill_target: '目标:亚瑟王'}
];// 提交
const handleSummit = () => {formRef.value.validate().then(async () => {try {const data = await state.form.file[0].arrayBuffer(); // 使用 arrayBuffer 避免中文乱码const workbook = XLSX.read(data, { type: 'buffer' });const outdata = XLSX.utils.sheet_to_json(workbook.Sheets[workbook.SheetNames[0]]);// 映射字段名并过滤掉不符合预期的数据const mappedData = outdata.map(row => {return Object.keys(row).reduce((targetMap, key) => {const mappedKey = fieldMap.sheet2json[key];if (mappedKey) {targetMap[mappedKey] = row[key];}return targetMap;}, {});}).filter(item => Object.keys(item).length > 0); // 过滤空对象console.log('------- 导入的数据 -------', mappedData);emits('submit', mappedData);handleClose();} catch (error) {}});
};// 模版下载
const handleDownload = () => {// 映射字段名并过滤掉不符合预期的数据const list = templateData.map(row => {return Object.keys(row).reduce((targetMap, key) => {const mappedKey = fieldMap.json2sheet[key];if (mappedKey) {targetMap[mappedKey] = row[key];}return targetMap;}, {});}).filter(item => Object.keys(item).length > 0); // 过滤空对象;const workSheet = XLSX.utils.json_to_sheet(list);const workBook = XLSX.utils.book_new();XLSX.utils.book_append_sheet(workBook, workSheet, '技能表');// 生成Excel文件并下载XLSX.writeFile(workBook, '技能表模板.xlsx');
};defineExpose({init
});
</script><style lang="less" scoped>
.upeate-field-warp {width: 100%;
}
</style><style lang="less">
.update-field-content-warp {padding: 40px 20px;.field-item {display: flex;align-items: center;label {min-width: 80px;}}
}
</style>

四、效果图:

原数据(图1)

导入组件(图2)

导出整理后的数据(图3)

模板下载(图4)

模板下载之后的文件(图5)

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

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

相关文章

微服务实战系列之玩转Docker(六)

前言 刚进入大暑&#xff0c;“清凉不肯来&#xff0c;烈日不肯暮”&#xff0c;空调开到晚&#xff0c;还是满身汗。——碎碎念 我们知道&#xff0c;仓库可见于不同领域&#xff0c;比如粮食仓库、数据仓库。在容器领域&#xff0c;自然也有镜像仓库&#xff08;registry&…

代码随想录——零钱兑换Ⅱ(Leetcode518)

题目链接 完全背包 class Solution {public int change(int amount, int[] coins) {int[] dp new int[amount 1];dp[0] 1;for(int i 0; i < coins.length; i){for(int j coins[i]; j < amount; j){dp[j] dp[j - coins[i]];}}return dp[amount];} }本题为组合问题…

uni-app AppStore Connect上传拒绝汇总

1.Guideline 2.3.3 - Performance - Accurate Metadata 问题是图片不对&#xff0c;最好是自己截图&#xff0c;然后用香蕉云编 上传图片合成图片 2.Guideline 5.1.2 - Legal - Privacy - Data Use and Sharing 解决办法&#xff1a;在uniapp manifest.json找到 APP常用其他…

【软考】系统集成项目管理工程师【第二版】

&#x1f44a;重要通知&#x1f44a; &#x1f44a; 1. 2024年中考上半年取消&#xff0c;改下半年&#x1f44a; &#x1f44a; 2. 2024下半年 使用《系统集成项目管理工程师教程》第三版&#x1f44a; &#x1f44a; 3. 为了方便大家学习&#xff0c;博主正在整理第三版 &am…

使用uniapp开发小程序(基础篇)

本文章只介绍微信小程序的开发流程&#xff0c;如果需要了解其他平台的开发的流程的话&#xff0c;后续根据情况更新相应的文章,也可以根据uniapp官网的链接了解不同平台的开发流程 HBuilderX使用&#xff1a;https://uniapp.dcloud.net.cn/quickstart-hx.html 开发工具 开始…

# OpenCV 图像预处理—形态学:膨胀、腐蚀、开运算、闭运算 原理详解

文章目录 形态学概念膨胀使用膨胀操作来修复裂痕示例代码关键解析&#xff1a; 腐蚀使用腐蚀操作消除噪点示例代码&#xff1a; 开运算—先腐蚀后膨胀闭运算—先膨胀后腐蚀 形态学概念 首先看这两张图片 一张图周围有大大小小的噪音和彩点&#xff0c;另一张图片中字母有间隙&…

php连接sql server

php连接sqlserver有三种方式 一&#xff1a;odbc连接&#xff0c;废话不多说直接上代码,封装了一个单例 <?php /*** odbcServer.php* Author: Erekys*/namespace App\Model; class odbcServer{public static $server;public static $username;public static $password;pu…

基于jeecgboot-vue3的Flowable流程仿钉钉流程设计器-发送信息服务处理

因为这个项目license问题无法开源&#xff0c;更多技术支持与服务请加入我的知识星球。 1、因为仿钉钉设计器里发送消息处理是一个服务任务&#xff0c;所以要根据这个服务任务进行处理 2、这里目前只对消息进行处理&#xff0c;就是用websocket的发送方式 输入相应的内容&…

go语言Gin框架的学习路线(十)

目录 GORM的CRUD教程 查询 普通查询 定义 User 结构体 查询所有用户 查询第一个用户 总结 条件查询 内联条件 额外查询选项 高级查询 链式操作 Scopes 多个立即执行方法 GORM的CRUD教程 CRUD 是 "Create, Read, Update, Delete"&#xff08;创建、查询…

AIoTedge边缘物联网平台,开启智能物联新架构

边缘物联网平台是一种将计算能力、数据处理和应用服务部署在网络边缘的解决方案&#xff0c;旨在提高响应速度、降低带宽需求和增强数据安全。根据搜索结果&#xff0c;边缘物联网平台应具备以下功能&#xff1a; 云边协同&#xff1a; 云边一体架构&#xff0c;通过云端管理边…

【BUG】已解决:Downgrade the protobuf package to 3.20.x or lower.

Downgrade the protobuf package to 3.20.x or lower. 目录 Downgrade the protobuf package to 3.20.x or lower. 【常见模块错误】 【解决方案】 欢迎来到英杰社区https://bbs.csdn.net/topics/617804998 欢迎来到我的主页&#xff0c;我是博主英杰&#xff0c;211科班出身…

【昇腾AI创新大赛集训营南京站学习笔记】-Ascend算子开发课程

昇腾AI创新大赛训练营 14:00-14:30 基础知识-理论课 一、CANN 、达芬奇架构和算子 1.AI Core逻辑架构 达芬奇架构包含三部分&#xff1a; 1&#xff09;计算类&#xff1a;矩阵计算单元&#xff08;两个矩阵扔进去相乘&#xff09;、向量计算单元、标量计算单元 2&#xff09;控…

基于单片机控制的变压器油压油温故障检测

摘 要 在电力系统的运行中&#xff0c;通过对其核心设备变压器的故障进行检测&#xff0c;以此能够及时、准确的发现变压器的故障&#xff0c;基于单片机控制的变压器油压油温的故障检测的方法&#xff0c;利用压力传感器、温度传感器对变压器的油压、油温进行采集并送入单片机…

vCenter 错误提示 “目标主机上的vmotion接口未配置”

vCenter 错误提示 “目标主机上的vmotion接口未配置” VMware 使用 vCenter 迁移 虚拟机报错 “目标主机上的 vMotion 接口未配置”&#xff0c;配置启用 vMotion 的步骤如下&#xff1a; &#xff08;END&#xff09;

leetcode3098. 求出所有子序列的能量和

官解 class Solution(object):# 定义常量mod int(1e9 7) # 模数&#xff0c;用于防止结果溢出inf float(inf) # 无穷大&#xff0c;用于初始化时的特殊值def sumOfPowers(self, nums, k):n len(nums) # 数组长度res 0 # 用于存储最终结果# 三维动态规划表&#xff0c;…

Nacos-2.4.0最新版本docker镜像,本人亲自制作,部署十分方便,兼容postgresql最新版本17和16,奉献给大家了

基于Postgresql数据库存储的nacos最新版本2.4.0,采用docker镜像安装方式 因业务需要,为了让nacos支持postgresql,特意花了两天时间修改了源码,然后制作了docker镜像,如果你也在找支持postgresql的nacos最新版本,恭喜你,你来的正好~ nacos-2.4.0 postgresql的数据库脚本…

Apache SeaTunnel快速入门及原理和实践(一)

一、概述 主要从以下6个方面进行&#xff1a; 对数据集成做一个简单的概括对 SeaTunnel 做简单的介绍介绍 SeaTunnel 当前的原理和架构演进对当前市面上一些比较常见的数据集成工具进行对比&#xff0c;来解读一下现在市面上已经有了那么多数据集成工具&#xff0c;为什么我们…

Django Web框架——01

目录 文章目录 目录 Django框架的介绍起源&现状Django的安装 创建Django项目创建项目的指令Django项目的目录结构settings.py 文件介绍 URL 介绍URL定义Django如何处理一个URL对应的请求视图函数(view) Django 路由配置path() 函数path转换器 re_path()函数 HTTP协议的请求…

CoAP——Libcoap安装和使用(Ubuntu22.04)

1、简介 CoAP&#xff08;Constrained Application Protocol&#xff09;是一种专为受限设备和网络设计的应用层协议。它类似于HTTP&#xff0c;但具有更轻量级的特性&#xff0c;适合用于物联网&#xff08;IoT&#xff09;环境中的低功耗和低带宽设备。Libcoap是一个轻量级的…

云计算实训12——配置web服务器、配置客户端服务器、配置DNS服务、实现DNS域名解析

一、配置web服务器 准备操作 首先在正式配置之前需要做以下操作 关闭防火墙 systemctl stop firewalld 永久关闭防火墙 systemctl disable firewalld 关闭selinux setenforce 0 永久关闭selinux vim /etc/selinux/config selinuxpermissive 还需要保证能够正常ping通www.bai…