个人博客纯手戳 vue3 nodejs mysql http://36.151.145.67:30000/一、导入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、templatea-form :modelstate.form nameform refformRef :label-col{ style: { width: 120px } } autocompleteoff :rulesrules a-form-item label导入文件上传 namefile :rulesrules.file div classfile-warp styleposition: relative a-upload stylemargin-left: 20px :file-liststate.form.file namefile :customRequestupload :beforeUploadbeforeUpload removehandleRemove accept.xlsx, .xls a-button typeprimary upload-outlined/upload-outlined 上传文件 /a-button /a-upload a-button typeprimary ghost styleposition: absolute; top: 0; left: 150px clickhandleDownload VerticalAlignBottomOutlined/VerticalAlignBottomOutlined 模版下载 /a-button /div /a-form-item /a-form2、scriptimport * 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_l163.com * Date: 2024-07-18 14:46:47 * LastEditors: snows_l snows_l163.com * LastEditTime: 2024-07-19 15:51:19 * FilePath: /digital-qiankun-you/cmdb/src/pages/ipSource/components/uploadFile.vue -- template div classupeate-field-warp a-modal width800px v-model:openopen :z-index10004 centered :title规划导入 template #footer a-button typeprimary clickhandleSummit确认/a-button /template div classupdate-field-content-warp a-form :modelstate.form nameform refformRef :label-col{ style: { width: 120px } } autocompleteoff :rulesrules a-form-item label导入文件上传 namefile :rulesrules.file div classfile-warp styleposition: relative a-upload stylemargin-left: 20px :file-liststate.form.file namefile :customRequestupload :beforeUploadbeforeUpload removehandleRemove accept.xlsx, .xls a-button typeprimary upload-outlined/upload-outlined 上传文件 /a-button /a-upload a-button typeprimary ghost styleposition: absolute; top: 0; left: 150px clickhandleDownload 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 langless scoped .upeate-field-warp { width: 100%; } /style style langless .update-field-content-warp { padding: 40px 20px; .field-item { display: flex; align-items: center; label { min-width: 80px; } } } /style四、效果图原数据图1导入组件图2导出整理后的数据图3模板下载图4模板下载之后的文件图5
阅读完成 · 觉得有帮助?