vue+elementui导入Excel文件(基于vue-element-admin中的uploadExcel组件)

vue+elementui导入Excel文件(基于vue-element-admin中的uploadExcel组件)

需求说明

实现Excel文件的上传,将文件传给后端完成数据的批量导入。并在前端进行解析,将上传的Excel回显到表格中。

备注:本功能仅实现了简单excel表格数据的导入,限制一次只能上传一个excel。

接下来就让我们开动吧!

第一步:构建页面

我这边就拿我正在做的一个项目举例,其中有一个功能是物品信息的管理。需要实现批量新增(即excel导入)。

首先我们在已有的页面上新增一个按钮,用以激活dialog。我这边将导入excel的部分放到dialog中。

<el-button
        class="filter-item"
        size="mini"
        type="primary"
        icon="el-icon-upload"
        @click="dialogVisible = true"
      >批量导入</el-button>
<el-dialog title="导入表单" :visible.sync="dialogVisible">
        <!--   导入excel,一会会将这里补充  -->
      </el-dialog>
data(){
    return{
        dialogVisible: false,  //dialog是否可见
    }
}

如下图所示,已经新增了一个批量导入的按钮。当我们点击时dialog会变为可见,即弹出dialog。

第二步:利用现成的组件

因为我这边用到的是el-admin的开源项目进行二次开发,其中涉及到的excel上传功能是来自于vue-element-admin开源项目的uploadExcel组件,所以我们直接去看封装好的组件,进行修改。

vue-element-admin的在线文档中,我们找到关于Excel的文档说明。如下图所示:

官方Demo(不涉及提交给后台的动作)

我们点击在线代码去查看示例代码。方便起见,我直接搬运过来了。

<template>
  <div class="app-container">
    <upload-excel-component :on-success="handleSuccess" :before-upload="beforeUpload" />
    <el-table :data="tableData" border highlight-current-row style="width: 100%;margin-top:20px;">
      <el-table-column v-for="item of tableHeader" :key="item" :prop="item" :label="item" />
    </el-table>
  </div>
</template>

<script>
import UploadExcelComponent from '@/components/UploadExcel/index.vue'
export default {
  name: 'UploadExcel',
  components: { UploadExcelComponent },
  data() {
    return {
      tableData: [],
      tableHeader: []
    }
  },
  methods: {
    beforeUpload(file) {
      const isLt1M = file.size / 1024 / 1024 < 1
      if (isLt1M) {
        return true
      }
      this.$message({
        message: 'Please do not upload files larger than 1m in size.',
        type: 'warning'
      })
      return false
    },
    handleSuccess({ results, header }) {
      this.tableData = results
      this.tableHeader = header
    }
  }
}
</script>

核心:UploadExcelComponent组件

可以看到,其中有一个UploadExcelComponent组件,我们继续去寻找该组件的代码。如下:

<template>
  <div>
    <input ref="excel-upload-input" class="excel-upload-input" type="file" accept=".xlsx, .xls" @change="handleClick">
    <div class="drop" @drop="handleDrop" @dragover="handleDragover" @dragenter="handleDragover">
      Drop excel file here or
      <el-button :loading="loading" style="margin-left:16px;" size="mini" type="primary" @click="handleUpload">
        Browse
      </el-button>
    </div>
  </div>
</template>

<script>
import XLSX from 'xlsx'
export default {
  props: {
    beforeUpload: Function, // eslint-disable-line
    onSuccess: Function// eslint-disable-line
  },
  data() {
    return {
      loading: false,
      excelData: {
        header: null,
        results: null
      }
    }
  },
  methods: {
    generateData({ header, results }) {
      this.excelData.header = header
      this.excelData.results = results
      this.onSuccess && this.onSuccess(this.excelData)
    },
    handleDrop(e) {
      e.stopPropagation()
      e.preventDefault()
      if (this.loading) return
      const files = e.dataTransfer.files
      if (files.length !== 1) {
        this.$message.error('Only support uploading one file!')
        return
      }
      const rawFile = files[0] // only use files[0]
      if (!this.isExcel(rawFile)) {
        this.$message.error('Only supports upload .xlsx, .xls, .csv suffix files')
        return false
      }
      this.upload(rawFile)
      e.stopPropagation()
      e.preventDefault()
    },
    handleDragover(e) {
      e.stopPropagation()
      e.preventDefault()
      e.dataTransfer.dropEffect = 'copy'
    },
    handleUpload() {
      this.$refs['excel-upload-input'].click()
    },
    handleClick(e) {
      const files = e.target.files
      const rawFile = files[0] // only use files[0]
      if (!rawFile) return
      this.upload(rawFile)
    },
    upload(rawFile) {
      this.$refs['excel-upload-input'].value = null // fix can't select the same excel
      if (!this.beforeUpload) {
        this.readerData(rawFile)
        return
      }
      const before = this.beforeUpload(rawFile)
      if (before) {
        this.readerData(rawFile)
      }
    },
    readerData(rawFile) {
      this.loading = true
      return new Promise((resolve, reject) => {
        const reader = new FileReader()
        reader.onload = e => {
          const data = e.target.result
          const workbook = XLSX.read(data, { type: 'array' })
          const firstSheetName = workbook.SheetNames[0]
          const worksheet = workbook.Sheets[firstSheetName]
          const header = this.getHeaderRow(worksheet)
          const results = XLSX.utils.sheet_to_json(worksheet)
          this.generateData({ header, results })
          this.loading = false
          resolve()
        }
        reader.readAsArrayBuffer(rawFile)
      })
    },
    getHeaderRow(sheet) {
      const headers = []
      const range = XLSX.utils.decode_range(sheet['!ref'])
      let C
      const R = range.s.r
      /* start in the first row */
      for (C = range.s.c; C <= range.e.c; ++C) { /* walk every column in the range */
        const cell = sheet[XLSX.utils.encode_cell({ c: C, r: R })]
        /* find the cell in the first row */
        let hdr = 'UNKNOWN ' + C // <-- replace with your desired default
        if (cell && cell.t) hdr = XLSX.utils.format_cell(cell)
        headers.push(hdr)
      }
      return headers
    },
    isExcel(file) {
      return /\.(xlsx|xls|csv)$/.test(file.name)
    }
  }
}
</script>

<style scoped>
.excel-upload-input{
  display: none;
  z-index: -9999;
}
.drop{
  border: 2px dashed #bbb;
  width: 600px;
  height: 160px;
  line-height: 160px;
  margin: 0 auto;
  font-size: 24px;
  border-radius: 5px;
  text-align: center;
  color: #bbb;
  position: relative;
}
</style>

这个组件是用来解析我们所上传的excel的,具体大家可以自行研究,主要是将excel中的内容解析成header和results,我们主要用解析后的信息回显给table。

在demo的基础上修改

了解了这些,我们就可以在dialog中完善相应的代码了。这边可以根据模板做修改。

<el-dialog title="导入表单" :visible.sync="dialogVisible">
        <div class="app-container">
          <div>
            <el-button
              class="filter-item"
              size="mini"
              type="primary"
              icon="el-icon-download"
              @click="downloadExceltoLocalFile()"
            >下载模板</el-button>
          </div>
          <upload-excel-component
            :on-success="handleSuccess"
            :before-upload="beforeUpload"
          />
          <el-table
            max-height="300"
            :data="tableData"
            border
            highlight-current-row
            style="width: 100%; margin-top: 20px"
          >
            <el-table-column
              v-for="item of tableHeader"
              :key="item"
              :prop="item"
              :label="item"
            >
              </template>
            </el-table-column>
          </el-table>
          <el-divider />
          <el-button
            style="float: right"
            type="primary"
            :loading="loading"
            @click="submitExcel()"
          >确认并导入</el-button>
        </div>
      </el-dialog>
  1. 这里我新增了一个下载模板的按钮,同样是调用后端接口去获得模板excel,然后点击进行下载。如果大家有需要我下次详细的讲怎么实现。

  2. 同时这边跟demo一样,用了uploadExcelComponent组件。怎么引入应该不用多说了吧。该组件提供了两个回调函数,在官方文档里都有描述。

    before-upload: 在上传前所做的动作

    on-success: 解析成功后触发的回调,我们在这里实现对表格中表头和内容的赋值

  3. 最后是一个确认的按钮,加入点击事件。

第三步:实现各个方法

  1. 下载模板按钮这边有一个downloadExceltoLocalFile()事件。
	downloadExceltoLocalFile() {
      crudMaterial
        .downloadExcel()
        .then((res) => {
          downloadFile(res, '物料模板', 'xlsx')
        })
        .catch((err) => {
          this.$message.error = err.message
        })
    },

你会发现缺了一个downloadFile的方法,该方法这个框架已经提供了,我们只需要import { downloadFile } from '@/utils/index'即可,具体的内容自行查阅相关资料或评论。其中

 crudMaterial
        .downloadExcel()

这个是我自己调后台的API接口,请自行修改。

  1. 组件的回调函数
// before-upload
    beforeUpload(file) {
      this.files = file
      console.log(this.files)
      const extension = file.name.substring(file.name.lastIndexOf('.') + 1)
      const isLt5M = file.size / 1024 / 1024 < 5
      if (extension !== 'xlsx' && extension !== 'xls') {
        this.$message({
          message: '只能上传Excel(即后缀是.xlsx或者.xls)的文件.',
          type: 'warning'
        })
        return false
      }
      if (isLt5M) {
        return true
      }

      this.$message({
        message: '请不要上传大于5MB的文件.',
        type: 'warning'
      })
      return false
    },

我这边只是一些简单的对后缀和大小的判断,大家根据实际自行修改。

 handleSuccess({ header, results }) {
      this.tableData = results
      this.tableHeader = header
    },

该回调即对提交的excel文件进行解析,同时给表格赋值。

  1. 点击提交的方法
submitExcel() {
      // 装载成formdata数据
      const formdata = new FormData()
      formdata.append('file', this.files, this.files.name)
      this.loading = true
      this.doImport(formdata)
    },
    async doImport(data) {
      try {
        const res = await crudMaterial.importMaterial(data)
        console.log('importMaterial', res)
        this.loading = false
        this.$message.success('导入成功')
      } catch (err) {
        console.log('importMaterial', err)
        this.loading = false
        this.$message.error('导入失败')
      }
    },

因为我们是要将excel传给后台服务器,所以我们需要新建一个formdata的变量,将formdata包装好数据传给后台,否则会出错。

doImport则是请求的方法,阅读应该没有难度。其中API接口如下:

至此,应该就差不多了。我们运行看一下效果。

点击浏览或者拖拽都可以实现文件的上传。

可以看到,上传的excel能成功回显,我们再点击确认进行提交。

提示导入成功。功能基本实现。

完整代码

api接口

import request from '@/utils/request'

export function downloadExcel() {
  return request({
    url: 'api/baseinfoMaterial/downloadExcel',
    method: 'get',
    responseType: 'blob'
  })
}

export function importMaterial(data) {
  return request({
    url: 'api/baseinfoMaterial/importExcel',
    method: 'post',
    data
  })
}

export default { downloadExcel, importMaterial }

index.vue 是这个页面所有的内容,按需取用

<template>
  <div class="app-container">
    <!--工具栏-->
    <div class="head-container">
      <div v-if="crud.props.searchToggle">
        <!-- 搜索 -->
        <label class="el-form-item-label">物料类别</label>
        <el-select
          v-model="query.modelName"
          clearable
          filterable
          placeholder="请选择"
          style="width: 185px"
          class="filter-item"
          @change="crud.toQuery"
        >
          <el-option
            v-for="item in dict.material_category"
            :key="item.id"
            :label="item.label"
            :value="item.value"
          />
        </el-select>
        <label class="el-form-item-label">物料名称</label>
        <el-input
          v-model="query.materialName"
          clearable
          size="small"
          placeholder="输入物料名称搜索"
          style="width: 185px"
          class="filter-item"
          @keyup.enter.native="crud.toQuery"
        />
        <label class="el-form-item-label">供应商</label>
        <el-input
          v-model="query.supplier"
          clearable
          placeholder="供应商"
          style="width: 185px"
          class="filter-item"
          @keyup.enter.native="crud.toQuery"
        />
        <label class="el-form-item-label">状态</label>
        <el-select
          v-model="query.enabled"
          clearable
          size="small"
          placeholder="请选择"
          class="filter-item"
          style="width: 90px"
          @change="crud.toQuery"
        >
          <el-option
            v-for="item in enabledTypeOptions"
            :key="item.key"
            :label="item.display_name"
            :value="item.key"
          />
        </el-select>
        <label class="el-form-item-label">创建时间</label>
        <date-range-picker v-model="query.createTime" class="date-item" />
        <rrOperation :crud="crud" />
      </div>
      <!--如果想在工具栏加入更多按钮,可以使用插槽方式, slot = 'left' or 'right'-->
      <crudOperation :permission="permission" />

      <el-button
        class="filter-item"
        size="mini"
        type="primary"
        icon="el-icon-upload"
        @click="dialogVisible = true"
        >批量导入</el-button
      >
      <el-dialog title="导入表单" :visible.sync="dialogVisible">
        <div class="app-container">
          <div>
            <el-button
              class="filter-item"
              size="mini"
              type="primary"
              icon="el-icon-download"
              @click="downloadExceltoLocalFile()"
              >下载模板</el-button
            >
          </div>
          <upload-excel-component
            :on-success="handleSuccess"
            :before-upload="beforeUpload"
          />
          <el-table
            max-height="300"
            :data="tableData"
            border
            highlight-current-row
            style="width: 100%; margin-top: 20px"
          >
            <el-table-column
              v-for="item of tableHeader"
              :key="item"
              :prop="item"
              :label="item"
            >
              <template slot-scope="scope">
                <template>
                  {{
                    scope.row[scope.column.property] === true
                      ? '启用'
                      : scope.row[scope.column.property] === false
                      ? '禁用'
                      : scope.row[scope.column.property]
                  }}
                </template>
              </template>
            </el-table-column>
          </el-table>
          <el-divider />
          <el-button
            style="float: right"
            type="primary"
            :loading="loading"
            @click="submitExcel()"
            >确认并导入</el-button
          >
        </div>
      </el-dialog>
    </div>
    <!--表单组件-->
    <el-dialog
      :close-on-click-modal="false"
      :before-close="crud.cancelCU"
      :visible.sync="crud.status.cu > 0"
      :title="crud.status.title"
      width="500px"
    >
      <el-form
        ref="form"
        :model="form"
        :rules="rules"
        size="small"
        label-width="80px"
      >
        <el-form-item label="物料名称" prop="materialName">
          <el-autocomplete
            v-model="form.materialName"
            style="width: 370px"
            :fetch-suggestions="querySearchMaterials"
            placeholder="请输入物料名称"
            :trigger-on-focus="false"
          >
            <template slot-scope="{ item }">
              <div>{{ (item.value = item.materialName) }}</div>
            </template>
          </el-autocomplete>
        </el-form-item>
        <el-form-item label="类别名称">
          <el-select
            v-model="form.modelName"
            filterable
            placeholder="请选择所属类别"
          >
            <el-option
              v-for="item in dict.material_category"
              :key="item.id"
              :label="item.label"
              :value="item.value"
            />
          </el-select>
        </el-form-item>
        <el-form-item label="物料编号" prop="materialNum">
          <el-input
            v-model="form.materialNum"
            style="width: 370px"
            placeholder="请输入物料编号"
          />
        </el-form-item>
        <el-form-item label="物料型号" prop="materialType">
          <el-input
            v-model="form.materialType"
            style="width: 370px"
            placeholder="请输入物料型号"
          />
        </el-form-item>
        <el-form-item label="品牌" prop="brand">
          <el-input
            v-model="form.brand"
            style="width: 370px"
            placeholder="请输入品牌"
          />
        </el-form-item>
        <el-form-item label="单位" prop="unit">
          <el-input
            v-model="form.unit"
            style="width: 370px"
            placeholder="请输入单位"
          />
        </el-form-item>
        <el-form-item label="计价方式" prop="pricingMode">
          <el-input v-model="form.pricingMode" style="width: 370px" disabled />
        </el-form-item>
        <el-form-item label="参考价格" prop="referencePrice">
          <el-input
            v-model="form.referencePrice"
            style="width: 370px"
            placeholder="请输入参考价格"
          >
            <template slot="append">元</template>
          </el-input>
        </el-form-item>
        <el-form-item label="供货商" prop="supplier">
          <el-input
            v-model="form.supplier"
            style="width: 370px"
            placeholder="请输入供货商"
          />
        </el-form-item>

        <el-form-item label="状态" prop="enabled">
          <el-radio
            v-for="item in dict.material_status"
            :key="item.id"
            v-model="form.enabled"
            :label="item.value === 'true'"
            >{{ item.label }}</el-radio
          >
        </el-form-item>
      </el-form>
      <div slot="footer" class="dialog-footer">
        <el-button type="text" @click="crud.cancelCU">取消</el-button>
        <el-button
          :loading="crud.status.cu === 2"
          type="primary"
          @click="crud.submitCU"
          >确认</el-button
        >
      </div>
    </el-dialog>
    <!--表格渲染-->
    <el-table
      ref="table"
      v-loading="crud.loading"
      lazy
      :data="crud.data"
      size="small"
      style="width: 100%"
      @selection-change="crud.selectionChangeHandler"
    >
      <el-table-column type="selection" width="55" />
      <el-table-column prop="modelName" label="类别名称">
        <template slot-scope="scope">
          {{ dict.label.material_category[scope.row.modelName] }}
        </template>
      </el-table-column>
      <el-table-column prop="materialNum" label="物料编号" />
      <el-table-column prop="materialName" label="物料名称" />
      <el-table-column prop="materialType" label="物料型号" />
      <el-table-column prop="brand" label="品  牌" />
      <el-table-column prop="unit" label="单位" />
      <el-table-column prop="pricingMode" label="计价方式" />
      <el-table-column prop="referencePrice" label="参考价格" />
      <el-table-column prop="supplier" label="供货商" />
      <el-table-column prop="enabled" label="状态" align="center">
        <template slot-scope="scope">
          <a-switch
            v-model="scope.row.enabled"
            checked-children="启用"
            un-checked-children="禁用"
            :disabled="scope.row.id === 1"
            @change="changeEnabled(scope.row, scope.row.enabled)"
          />
        </template>
      </el-table-column>

      <el-table-column prop="createTime" label="创建时间" />
      <el-table-column
        v-if="checkPer(['admin', 'material:edit', 'material:del'])"
        label="操作"
        width="150px"
        align="center"
      >
        <template slot-scope="scope">
          <udOperation :data="scope.row" :permission="permission" />
        </template>
      </el-table-column>
    </el-table>
    <!--分页组件-->
    <pagination />
  </div>
</template>

<script>
import crudMaterial from '@/api/record/material'
import CRUD, { presenter, header, form, crud } from '@crud/crud'
import rrOperation from '@crud/RR.operation'
import crudOperation from '@crud/CRUD.operation'
import udOperation from '@crud/UD.operation'
import pagination from '@crud/Pagination'
import DateRangePicker from '@/components/DateRangePicker'
import UploadExcelComponent from '@/components/UploadExcel/index.vue'
import { downloadFile } from '@/utils/index'
const defaultForm = {
  id: '',
  materialNum: null,
  materialName: null,
  materialType: null,
  unit: null,
  pricingMode: '加权平均法',
  referencePrice: null,
  supplier: null,
  createTime: null,
  enabled: true,
  modelName: null,
  brand: null
}
export default {
  name: 'Material',
  components: {
    pagination,
    crudOperation,
    rrOperation,
    udOperation,
    DateRangePicker,
    UploadExcelComponent
  },
  mixins: [presenter(), header(), form(defaultForm), crud()],
  dicts: ['material_category', 'material_status'],
  cruds() {
    return CRUD({
      title: '物料管理',
      url: 'api/baseinfoMaterial',
      sort: 'id,desc',
      crudMethod: { ...crudMaterial }
    })
  },
  data() {
    /* 金额格式校验  */
    var validatePrice = (rule, value, callback) => {
      const reg = /(^[1-9]\d*(\.\d{1,2})?$)|(^0(\.\d{1,2})?$)/
      if (value === '' || value === undefined || value == null) {
        callback()
      } else {
        if (!reg.test(value) && value !== '') {
          callback(new Error('请输入正确的价格!整数或保留两位小数'))
        } else {
          callback()
        }
      }
    }
    return {
      tableData: [],
      tableHeader: [],
      dialogVisible: false,
      loading: false,
      files: [],
      enabledTypeOptions: [
        { key: 'true', display_name: '正常' },
        { key: 'false', display_name: '禁用' }
      ],
      permission: {
        add: ['admin', 'material:add'],
        edit: ['admin', 'material:edit'],
        del: ['admin', 'material:del']
      },
      rules: {
        materialName: [
          {
            required: true,
            message: '请输入物料名称',
            trigger: 'blur'
          }
        ],
        materialNum: [
          { required: true, message: '请输入物料编号', trigger: 'blur' }
        ],
        materialType: [
          { required: true, message: '请输入物料型号', trigger: 'blur' }
        ],
        brand: [{ required: true, message: '请输入品牌', trigger: 'blur' }],
        unit: [{ required: true, message: '请输入单位', trigger: 'blur' }],
        referencePrice: [
          { required: true, message: '请输入参考价格', trigger: 'blur' },
          {
            validator: validatePrice,
            trigger: 'blur'
          }
        ]
      },
      queryTypeOptions: [
        { key: 'materialName', display_name: '物料名称' },
        { key: 'materialType', display_name: '物料型号' },
        { key: 'supplier', display_name: '供货商' },
        { key: 'modelName', display_name: '类别名称' }
      ]
    }
  },
  mounted() {
    this.loadAll()
  },

  methods: {
    // 导入
    submitExcel() {
      // 装载成formdata数据
      const formdata = new FormData()
      formdata.append('file', this.files, this.files.name)
      this.loading = true
      this.doImport(formdata)
    },
    async doImport(data) {
      try {
        const res = await crudMaterial.importMaterial(data)
        console.log('importMaterial', res)
        this.loading = false
        this.$message.success('导入成功')
      } catch (err) {
        console.log('importMaterial', err)
        this.loading = false
        this.$message.error('导入失败')
      }
    },
    // 导入功能
    beforeUpload(file) {
      this.files = file
      console.log(this.files)
      const extension = file.name.substring(file.name.lastIndexOf('.') + 1)
      const isLt5M = file.size / 1024 / 1024 < 5
      if (extension !== 'xlsx' && extension !== 'xls') {
        this.$message({
          message: '只能上传Excel(即后缀是.xlsx或者.xls)的文件.',
          type: 'warning'
        })
        return false
      }
      if (isLt5M) {
        return true
      }

      this.$message({
        message: '请不要上传大于5MB的文件.',
        type: 'warning'
      })
      return false
    },
    transExcel(results) {
      const mapInfo = {
        类别名称: 'modelName',
        物料编号: 'materialNum',
        物料名称: 'materialName',
        物料型号: 'materialType',
        单位: 'unit',
        计价方式: 'pricingMode',
        参考价格: 'referencePrice',
        供货商: 'supplier',
        状态: 'enabled',
        品牌: 'brand'
      }
      return results.map((zhObj) => {
        const enObj = {}
        const zhKeys = Object.keys(zhObj)
        zhKeys.forEach((zhKey) => {
          const enKey = mapInfo[zhKey]
          enObj[enKey] = zhObj[zhKey]
        })
        return enObj
      })
    },
    handleSuccess({ header, results }) {
      this.tableData = results
      this.tableHeader = header
    },
    // 改变状态
    changeEnabled(data, val) {
      this.$confirm(
        '此操作将 "' +
          this.dict.label.material_status[val] +
          '" ' +
          data.materialName +
          '仓库, 是否继续?',
        '提示',
        {
          confirmButtonText: '确定',
          cancelButtonText: '取消',
          type: 'warning'
        }
      )
        .then(() => {
          // eslint-disable-next-line no-undef
          crudMaterial
            .edit(data)
            .then(() => {
              // eslint-disable-next-line no-undef
              this.crud.notify(
                this.dict.label.material_status[val] + '成功',
                'success'
              )
            })
            .catch((err) => {
              data.enabled = !data.enabled
              console.log(err.data.message)
            })
        })
        .catch(() => {
          data.enabled = !data.enabled
        })
    },

    loadAll() {
      crudMaterial.getAllMaterial().then((res) => {
        this.materials = res.content
      })
    },

    downloadExceltoLocalFile() {
      crudMaterial
        .downloadExcel()
        .then((res) => {
          downloadFile(res, '物料模板', 'xlsx')
        })
        .catch((err) => {
          this.$message.error = err.message
        })
    },

    querySearchMaterials(queryString, cb) {
      var materials = this.materials
      var results = queryString
        ? materials.filter(this.createFilter(queryString))
        : materials
      cb(results)
    },

    // 查询输入字符是否存在
    createFilter(queryString) {
      return (form) => {
        return (
          form.materialName.toLowerCase().indexOf(queryString.toLowerCase()) !==
          -1
        )
      }
    },
    // 钩子:在获取表格数据之前执行,false 则代表不获取数据
    [CRUD.HOOK.beforeRefresh]() {
      return true
    }
  }
}
</script>

<style scoped></style>

PS:注意一个细节

该图是后端controller层提供的接口,这边需要额外注意一点。这边的参数file需要和前面formdata中的第一个参数对应。否则会出现400错误。

总结

这次的开发仅仅是在单个页面上进行编写,还没有封装成一个通用的组件,同时由于本人能力有限,可能会存在一些疏漏,出现BUG。还望大家能够指出。

参考资料

vue-element-admin开源项目,文档地址
el-admin开源项目,文档地址
element-ui, 文档地址
element-ui/vue-element-admin上传excel等文件到服务器,文章地址

posted @ 2021-12-24 17:36  陆黎  阅读(7561)  评论(1编辑  收藏  举报