Vue3实现动态导入Excel表格数据的方法详解

1.  前言

在开发工作过程中,我们会遇到各种各样的表格数据导入,大部分我们的解决方案:提供一个模板前端进行下载,然后按照这个模板要求进行数据填充,最后上传导入,这是其中一种解决方案。个人认为还有另外一种解决方案,不一定会前面的方案好,方便,但是可以减少人为操作,减少出错,更为通用,就是进行动态数据导入,前端进行自定义导入数据,配置数据对应关系,最后提交导入结果。

2.  如何实现

2.1使用技术

后台使用.Net6.0,前端使用Vue3

2.2实现思路

  • 前端通过Excel表格数据导入,导入后客户可以进行数据编辑(未实现)客户数据确认后进行数据回写主页面
  • 设置数据对应关系,也就是后台所需数据格式和前台数据格式进行绑定
  • 数据校验,进行数据提交

2.3具体实现方案

2.3.1导入Excel数据

创建列表页面,页面主要布局如下

Table需要绑定的列是未知的,所以el-table绑定的el-table-column是需要动态进行加载,动态定义表格以及变量


  
  
const state = reactive({
colunm: [{key: "", lable: ""}],
});

点击导入报名数据,弹出上传数据页面

Vue3实现动态导入Excel表格数据的方法详解_第1张图片

这一块的功能在之前的一篇文章有写过:.Net6.0+Vue3实现数据简易导入功能全过程

子组件的核心代码

页面布局:

变量定义:

const state = reactive({
  tempTableData: [{}],//临时存储全部数据
  searchInput: { PageIndex: 1, PageSize: 10 },
  tableData: { data: [{}], total: 0 },//表格加载当前页面数据
  dialogVisible: false,
  colunm: [{ key: '', lable: '' }]
});

父页面调用方法,进行表格列头加载,初始化表格数据:

const childMethod = (data) => {
  state.colunm = data;
  state.tableData.data = [];
  state.dialogVisible = true;
}

绑定表格方法,前端进行分页数据处理:(这里可能会有性能问题,暂时没有仔细探究)

const getData = () => {
  const tempData: any = [];
  state.tempTableData.forEach((value, index) => {
    if (index >= ((state.searchInput.PageIndex - 1) * state.searchInput.PageSize) && index < ((state.searchInput.PageIndex) * state.searchInput.PageSize)) {
      tempData.push(value);
    }
  });
  state.tableData.data = tempData;
  state.tableData.total = state.tempTableData.length;
}

提交数据回写父组件方法

const submit = () => {
  console.log(state.tempTableData);
  context.emit('childClick', state.tempTableData,state.colunm)
}

上传Excel读取数据方法,主要动态绑定列以及导入的数据

const uploadChange = async (file) => {
  let dataBinary = await readFile(file.raw)
  let workBook = XLSX.read(dataBinary, { type: 'binary', cellDates: true })
  let workSheet = workBook.Sheets[workBook.SheetNames[0]]
  let data: any = XLSX.utils.sheet_to_json(workSheet)

  let mycolunm={};
  Object.setPrototypeOf(mycolunm,data[0]);
  state.colunm=[];
  for(let key in mycolunm){
    state.colunm.push( { lable: key, key: key })
  }
  
  let tHeader = state.colunm.map(obj => obj.lable)
  let filterVal = state.colunm.map(obj => obj.key)
  tHeader.map(val => filterVal.map(obj => val[obj]))
  const tempData: any = [];
  data.forEach((value) => {
    const ob = {};
    tHeader.forEach((item, index) => {
      ob[filterVal[index]] = value[item].toString();
    })
    tempData.push(ob);
  })
  state.tempTableData = tempData;
  getData();
}

这里导入数据后,会调用主组件方法(dataUploadchildClick)用于回写主组件表格数据,列头等数据

const dataUploadchildClick = (data, colunm) => {
  state.colunm = colunm;
  state.tempData = data;
  getData();
  dataUpload.value.cancel();
};

2.3.2设置数据对应关系

定义后台需要的列

SelectData: [
  {key: 'zkzh', type: '', value: '', selectValue: '', title: '准考证号'},
  {key: 'zjlb', type: '', value: '', selectValue: '', title: '证件类别'},
  {key: 'zjhm', type: '', value: '', selectValue: '', title: '证件号码'},
  {key: 'ksxm', type: '', value: '', selectValue: '', title: '考生姓名'},
  {key: 'xb', type: '', value: '', selectValue: '', title: '性别'},
  {key: 'ss', type: '', value: '', selectValue: '', title: '省市'},
  {key: 'kq', type: '', value: '', selectValue: '', title: '考区'},
  {key: 'kdh', type: '', value: '', selectValue: '', title: '考点号'},
  {key: 'kdmc', type: '', value: '', selectValue: '', title: '考点名称'},
  {key: 'kch', type: '', value: '', selectValue: '', title: '考场号'},
  {key: 'kchdz', type: '', value: '', selectValue: '', title: '考场地址'},
  {key: 'zwh', type: '', value: '', selectValue: '', title: '座位号'},
  {key: 'chc', type: '', value: '', selectValue: '', title: '场次'}
]

创建Select组件,组件核心代码

页面布局部分



  



  

接受参数定义

props: {
  itemKey: String,
  name: String,
  type: String,
  value: String,
  selectValue: String,
  colunm: Object
},

页面变量定义,这里定义的默认option主要有三个

  • 0 固定值,这一列为固定值,不从表格中读取
  • 1 下拉框,从导入数据中选择
  • 2 自动生成,这里主要是特殊业务,可以进行自定义扩展
const state = reactive({
  value: ref(''),
  type: ref(''),
  selectValue: ref([]),
  ValueOptions:[{}],
  options: [
    {
      value: '0',
      label: '固定值',
    },
    {
      value: '1',
      label: '下拉框',
    },
    {
      value: '2',
      label: '自动生成',
    },
  ],
});

监听下拉框选择类型:

watch(() => state.type, (newVal) => {
      context.emit('update:type', newVal);
    }
);

监听下拉框选择固定,文本框输入的值:

watch(() => state.value, (newVal) => {
  context.emit('update:value', newVal)
})

监听下拉框选择下拉框,后面下拉框选择的值:

watch(() => state.selectValue, (newVal) => {
  context.emit('update:selectValue', newVal)
})

监听表格的列,动态加载下拉框绑定的值:

watch(() => props.colunm, (newVal: any) => {
  state.ValueOptions=newVal;
})

最终的效果:

Vue3实现动态导入Excel表格数据的方法详解_第2张图片

父页面进行引用