Bootstrap

【前端】excel文件对比

需求描述

通过代码比对现文件与原文件的异常情况,并通过文件导出。

实现逻辑

  1. 将上传文件转为Array格式
  2. 进行数据比对
  3. 将处理好的文件展示在表格上,或者导出

文件上传

<script>
import XLSX from 'xlsx'
export default {
  name: 'CompareExcel',
  data () {
    return {
      originData: [], // 原始数据
      compareData: [], // 对比数据
    }
  },

  methods: {
    onChangeFile (file, type) {
      const fileReader = new FileReader()
      fileReader.onload = (e) => {
        const data = new Uint8Array(e.target.result)
        const { SheetNames, Sheets } = XLSX.read(data, { type: 'array' })
        const workSheet = Sheets[SheetNames[0]]
        const sheetRows = XLSX.utils.sheet_to_json(workSheet)
        if (type === 'origin') {
          const originTitle = sheetRows[0]
          const originTitleKeys = Object.keys(originTitle)
          const originTitleValues = Object.values(originTitle)
          sheetRows.forEach((item, index) => {
            if (index !== 0) {
              let newItem = {}
              originTitleValues.forEach((key, keyIndex) => {
                newItem[key] = item[originTitleKeys[keyIndex]] || null
              })
              this.originData.push(newItem)
            }
          })
        } else {
          this.compareData = sheetRows
        }
      }
      fileReader.readAsArrayBuffer(file.raw)
    },
  }
}
</script>

这里提供了两种文件的处理格式,如果是基本的Excel,在XLSX.utils.sheet_to_json将其转为json文件后,直接存储就可以了,但是在线文档下载为Excel后,数据格式并不是键值对,因此需要通过处理,将其变成[{ name:value }]的这种格式。

textExcel: [
        { 表格: '', _empty1: '序号', _empty2: '姓名', _empty3: '年龄', _empty4: '性别', _empty5: '备注' },
        { 表格: '', _empty1: '1', _empty2: '张三', _empty3: '18', _empty4: '男', _empty5: '测试1' },
        { 表格: '', _empty1: '2', _empty2: '李四', _empty3: '20', _empty4: '女', _empty5: '测试2' },
        { 表格: '', _empty1: '3', _empty2: '王五', _empty3: '22', _empty4: '男', _empty5: '测试3' },
      ]

数据比对

   /** 对比 */
    onCompare () {
      this.resultData = []
      console.log(this.originData, this.compareData, 'this.originData, this.compareData')
      // 通过姓名进行对比
      this.compareData.forEach(item => {
        const findItem = this.originData.find(originItem => originItem['姓名'] === item['姓名'])
        if (findItem) {
          let errorMsg = []
          const compareKey = Object.keys(item)
          compareKey.forEach(key => {
            if (findItem[key] !== item[key]) {
              errorMsg.push(`${key}不同,原数据为${findItem[key]},对比数据为${item[key]}`)
            }
          })

          // 如果有不同数据
          if (errorMsg.length > 0) {
            const finalItem = { origin: findItem, compare: item, error: errorMsg }
            this.resultData.push(finalItem)
          }
        }
        // else {
        //   const finalItem = { origin: null, compare: item, error: ['未找到对应数据'] }
        //   this.resultData.push(finalItem)
        // }
      })
      // 处理报错数据
      const addErrorData = this.resultData.map(x => ({ ...x.compare, error: x.error.join(';') }))
      const header = Object.keys(addErrorData[0])

      addErrorData.forEach(item => {
        let newItem = []
        header.forEach(key => {
          newItem.push(item[key])
        })
        this.showData.push(newItem)
      })
      console.log(addErrorData, 'addErrorData', header,this.showData)

      // 导出时,数据为定义好的全部数据格式
      // 表头 = ["id", "姓名", "年龄"]
      // 内容 = [ [1, "张三", 18],  [2, "李四",  20 ] ]
      exportJsonToExcel({
        multiHeader: [],
        header: header,
        data: this.showData,
        filename: `对比结果`
      })

    },

数据比对的逻辑是,首先确定一个key值作为比对的点,然后找到两条匹配的数据,然后再通过Object.keys寻找name,将相同name的value值进行比对,如果不一致,增加一条error信息输出,这里比对可以使用更细节的方法,比如大小写忽略等等,按实际业务情况去做。


最后的addErrorData就是处理好的数据,可以直接在页面上输出,也可以再导出为Excel。

文件导出

 addErrorData.forEach(item => {
        let newItem = []
        header.forEach(key => {
          newItem.push(item[key])
        })
        this.showData.push(newItem)
      })
      console.log(addErrorData, 'addErrorData', header,this.showData)

      // 导出时,数据为定义好的全部数据格式
      // 表头 = ["id", "姓名", "年龄"]
      // 内容 = [ [1, "张三", 18],  [2, "李四",  20 ] ]
      exportJsonToExcel({
        multiHeader: [],
        header: header,
        data: this.showData,
        filename: `对比结果`
      })

使用exportJsonToExcel导出文件,这里的data如注释所示,数据必须是像Excel内部一样形成每行的数据数组,才能成功导出。因此先要

悦读

道可道,非常道;名可名,非常名。 无名,天地之始,有名,万物之母。 故常无欲,以观其妙,常有欲,以观其徼。 此两者,同出而异名,同谓之玄,玄之又玄,众妙之门。

;