如果本文对您有帮助,希望点个赞,建立下友谊关系。

前端使用xlsx导出导入文件

就vue来讲:

第一步首先要下载xlsx

yarn add xlsx 
yarn add xlsx-style

导入会用到的插件文件解析

yarn add worker-loader
yarn add uuid

下载好了过后,我们需要写个解析的导入文件:命名为xlsx.worker.js,然后需要引入到main.js中

xlsx.worker.js代码附上:

import { read, utils } from 'xlsx';

self.onmessage = e => {
  const { file, id, keyMaps } = e.data;
  const reader = new FileReader();
  reader.onload = e => {
    const workbook = read(e.target.result, {type: 'binary'});
    const Sheets = workbook.Sheets;
    const list = Object.keys(Sheets).map((key, index) => {
      const list = utils.sheet_to_json(Sheets[key]);
      // 某张表的label和key的map
      const keyMap = keyMaps[index];
      return list.map(item => {
        const row = {};
        for (let key in item) {
          const column = keyMap[key];
          const value = item[key];
          if (column) {
            if (typeof column === 'string') {
              row[column] = value + '';
            } else {
              const { type, key: prop } = column;
              if (type === 'number') {
                row[prop] = isNaN(value * 1) ? value : value * 1;
              } else {
                row[prop] = value;
              }
            }
          } else {
            // row[prop] = value;
          }
        }
        return row;
      });
    })
    self.postMessage({ id, list });
  }
  reader.readAsArrayBuffer(file);
}

把该文件引入到main.js中

import XLSXWorker from '@/workers/xlsx.worker';
Vue.prototype.$workers = {
  xlsx: new XLSXWorker()
};

好了,这样我们就完成引入部分了,就可以开始做导入功能了。

在.vue文件中写导入和导出功能附上代码:

<template>
  <a-modal
      title="商品导入"
      :width="1200"
      v-on="$listeners"
      :confirm-loading="loadingBtn"
      :visible="importVisible"
      @cancel="handleCancel"
      @ok="submitAdd">
    <a-form-model :label-col="{ span: 6 }" 
            :wrapper-col="{ span: 16 }"
            style="padding: 0 0 0 20px;">
      <BaseTitle title="设置商品" />
      <a-row>
        <a-col :span="9">
          <a-form-item :label-col="{ span: 4 }" :wrapper-col="{ span: 18 }">
            <a-button type="link" class="right-a" @click="downloadTemplete">下载商品导入模板</a-button>
            <a-upload-dragger name="file" 
                    :file-list="fileList"
                    :multiple="false"
                    :beforeUpload="onBeforeUpload"
                    accept=".xls,.xlsx,.xlsm"
                    action="">
              <div>
                <a-icon type="cloud-upload" style="font-size: 24px; color: @primary-color;" />
                <p>点击或拖拽商品文件导入</p>
              </div>
            </a-upload-dragger>
          </a-form-item>
        </a-col>
      </a-row>
      <BaseTitle title="导入结果" />
      <a-row>
        <a-table
          :columns="columns"
          :data-source="tableData"
          size="small" />
      </a-row>
    </a-form-model>
  </a-modal>
</template>

<script>
  import { columns } from '@/tables/goods/goodsImport';
  import BaseTitle from '@/components/BaseTitle/index.vue'
  import {goodsService} from '@/service/index'
  import * as xlsx from 'xlsx';
  import { v4 as uuid } from 'uuid';

  const keyMaps = [
    {
      '商品名称(必填)': 'cnName',
      '仓库id(必填)': 'warehouseId',
      '品牌id(必填)': 'brandId',
      '国家编码(必填)': 'originCountryCode',
      '商品规格(必填)': 'goodsModel',
      '毛重(克)(必填)': { key: 'netWeight', type: 'number' },
      '净重(克)(必填)': { key: 'grossWeight', type: 'number' },
      '币种(必填)': 'currency',
      '条形码(必填)': 'barCode',
      '到期时间(必填)': 'expirationDate',
      'hsCode': 'hsCode',
      '销售价格': { key: 'priceSales', type: 'number' },
      '成本价格': { key: 'priceCost', type: 'number' },
      '法定计量单位': 'unit',
      '商品配料': 'goodsComponent',
      '包装类型': 'packageType'
    },
    { '仓库名称': 'warehouseTitle', '仓库编码': 'id' },
    { '品牌名称': 'brandName', '仓库编码': 'brandId' },
    { '国家': 'cnname', '国家编码': 'isoNcode' },
    { '币种名称': 'shortCnname', '币种编码': 'customsCode' },
    { '计量单位': 'shortCnname', '计量单位编码': 'customsCode' }
  ];

  export default {
    components: { BaseTitle },
    model: {
      prop: 'importVisible',
      event: 'change'
    },
    props: {
      importVisible: {type: Boolean, default: false},
      importData: {type:Object, default: ()=> ({})}
    },
    data() {
      return {
        fileList: [],
        tableData: [],
        columns,
        rowSelection: {},
        worderId: uuid(),//商品ID
        loadingBtn: false
      }
    },
    mounted() {
      //导入数据解析结果监听
      this.$workers.xlsx.onmessage = res => {
        const { id, list } = res.data;
        if (id !== this.worderId) {
          return;
        }
        this.tableData = list[0];
      }
    },
    methods: {
      //下载商品导入模板
      downloadTemplete() {
        //商品列表-sheet1
        let newList = [{
          '商品名称(必填)': '',
          '仓库id(必填)': '',
          '品牌id(必填)': '',
          '国家编码(必填)': '',
          '商品规格(必填)': '',
          '毛重(克)(必填)': 0,
          '净重(克)(必填)': 0,
          '币种(必填)': '',
          '条形码(必填)': '',
          '到期时间(必填)': '',
          'hsCode': '',
          '销售价格': 0,
          '成本价格': 0,
          '法定计量单位': '',
          '商品配料': '',
          '包装类型': ''
        }]
        //仓库对应编码
        const warehouseList = []
        const warehouseName = {
          warehouseTitle: '仓库名称',
          id: '仓库编码'
        }
        // 转换
        if(this.importData.warehouseList.length) {
          this.importData.warehouseList.forEach(item=>{
            let obj = {};
            for(let key in item){
              if(warehouseName[key]){
                obj[warehouseName[key]] = item[key];
              }
            }
            warehouseList.push(obj);
          })
        } else {
          warehouseList.push({'仓库名称': '', '仓库编码': ''});
        }
        
        //品牌对应编码
        const bransList = []
        const brandName = {
          brandName: '品牌名称',
          brandId: '品牌编码'
        }
        // 转换
        if(this.importData.brandList.length) {
          this.importData.brandList.forEach(item=>{
            let obj = {};
            for(let key in item){
              if(brandName[key]){
                obj[brandName[key]] = item[key];
              }
            }
            bransList.push(obj);
          })
        } else {
          bransList.push({'品牌名称': '', '品牌编码': ''});
        }

        //国家对应编码
        const countryList = []
        const countryName = {
          cnname: '国家',
          isoNcode: '国家编码'
        }
        // 转换
        if(this.importData.addressList.length) {
          this.importData.addressList.forEach(item=>{
            let obj = {};
            for(let key in item){
              if(countryName[key]){
                obj[countryName[key]] = item[key];
              }
            }
            countryList.push(obj);
          })
        } else {
          countryList.push({'国家': '', '国家编码': ''});
        }

        //币种对应编码
        const currencyList = []
        const currencyName = {
          shortCnname: '币种名称',
          customsCode: '币种编码'
        }
        // 转换
        if(this.importData.currencyList.length) {
          this.importData.currencyList.forEach(item=>{
            let obj = {};
            for(let key in item){
              if(currencyName[key]){
                obj[currencyName[key]] = item[key];
              }
            }
            currencyList.push(obj);
          })
        } else {
          currencyList.push({'币种名称': '', '币种编码': ''});
        }

        //法定计量单位对应编码
        const unitList = []
        const unitName = {
          shortCnname: '计量单位',
          customsCode: '计量单位编码'
        }
        // 转换
        if(this.importData.unitList.length) {
          this.importData.unitList.forEach(item=>{
            let obj = {};
            for(let key in item){
              if(unitName[key]){
                obj[unitName[key]] = item[key];
              }
            }
            unitList.push(obj);
          })
        } else {
          unitList.push({'计量单位': '', '计量单位编码': ''});
        }

        let sheet1 = xlsx.utils.json_to_sheet(newList);//商品列表
        let wscols = [    // 每列不同宽度px
          { wch: 15 },{ wch: 15 },{ wch: 15 },
          { wch: 15 },{ wch: 15 },{ wch: 15 },
          { wch: 15 },{ wch: 15 },{ wch: 15 },
          { wch: 15 },{ wch: 15 },{ wch: 15 },
          { wch: 15 },{ wch: 15 },{ wch: 15 },
          { wch: 15 },{ wch: 15 }
        ];
        // workbook.SheetNames[0]获取到到是文件里的到第一个表格
        sheet1["!cols"] = wscols;
        let wsrows = [{ hpx: 20 }];  // 每行固定高度px
        for (let i = 0; i <= this.total; i++) {   // total  列表条数
          wsrows.push({ hpx: 20 });
        }
        sheet1["!rows"] = wsrows;
        let sheet2 = xlsx.utils.json_to_sheet(warehouseList);//仓库列表
        let sheet3 = xlsx.utils.json_to_sheet(bransList);//品牌列表
        let sheet4 = xlsx.utils.json_to_sheet(countryList);//国家列表
        let sheet5 = xlsx.utils.json_to_sheet(currencyList);//币种列表
        let sheet6 = xlsx.utils.json_to_sheet(unitList);//法定计量单位列表
        let book = xlsx.utils.book_new();
        xlsx.utils.book_append_sheet(book, sheet1, "商品列表");
        xlsx.utils.book_append_sheet(book, sheet2, "仓库对应编码");
        xlsx.utils.book_append_sheet(book, sheet3, "品牌对应编码");
        xlsx.utils.book_append_sheet(book, sheet4, "国家对应编码");
        xlsx.utils.book_append_sheet(book, sheet5, "币种对应编码");
        xlsx.utils.book_append_sheet(book, sheet6, "法定计量单位对应编码");
        xlsx.writeFile(book, `iwms_goods_import_template.xlsx`);
      },
      //上传处理
      onBeforeUpload(file, fileList) {
        this.fileList = [fileList.pop()];
        this.$workers.xlsx.postMessage({
          id: this.worderId,
          keyMaps,
          file,
        });
        return false;
      },
      //保存
      submitAdd() {
        if(!this.fileList.length){
          this.$message.error('请上传文件')
        }
        this.loadingBtn = true
        goodsService.goodsAddto({goodsData: this.tableData}).then(res => {
          this.loadingBtn = false
          if(res.code !== 200) return
          this.$message.success('导入成功')
          this.handleCancel()
          this.$emit('confirm', confirm);
        })
      },
      handleCancel() {
        this.$emit('cancel');
        this.fileList = [];
        this.tableData = []
      }
    }
  }
</script>
<style scoped lang="less">
.right-a { margin-right: 10px;}
/deep/.ant-btn-link{padding:0;}
</style>
View Code

下载的模板图片:

 

 

最后图片:

 

posted @ 2022-05-13 10:54  一只喵喵  阅读(820)  评论(0编辑  收藏  举报