Xử lý nhập file Excel với Element UI trong Vue.js

Thiết kế giao diện: (Chức năng chọn file được đặt bên trong hộp thoại - khi người dùng nhấn nút nhập, hộp thoại sẽ hiển thị, người dùng cần tải mẫu trước, sau đó chọn file và nhấn nút gửi để tải lên)

<div class="excel-import-container">
  <el-dialog 
    :title="dialogTitle" 
    :visible.sync="showDialog" 
    :modal-append-to-body="false"
  >
    <el-upload
      :ref="uploadRef"
      v-loading="isUploading"
      class="file-uploader"
      :action="uploadUrl"
      :on-preview="handlePreview"
      :on-remove="handleFileRemove"
      :file-list="selectedFiles"
      :headers="requestHeaders"
      name="document"
      accept=".xlsx"
      :on-error="handleUploadError"
      :on-success="handleUploadSuccess"
      :auto-upload="false"
      :http-request="customUpload"
      :on-change="onFileChange"
    >
      <el-button slot="trigger" size="small" type="primary">Chọn tệp</el-button>
      <el-button style="margin-left: 10px;" size="small" type="success" @click="downloadTemplate">Tải mẫu</el-button>
      <div slot="tip" class="el-upload__tip">Vui lòng tải mẫu trước, sau đó chọn tệp để tải lên!</div>
    </el-upload>
    <div slot="footer" class="dialog-footer">
      <el-button class="cancel-btn" @click="cancelImport">Hủy</el-button>
      <el-button type="primary" class="submit-btn" @click="submitFile">Gửi</el-button>
    </div>
  </el-dialog>
</div>

Chức năng tải mẫu và nhập file:

<script>
import eventBus from '@/utils/eventBus'
import { commonMixin } from '@/utils/mixins'
import { initializeData, initializeChildren } from '@/utils/helpers'
import { sendFile } from '@/api/services/dataImport'

export default {
  name: 'ExcelImporter',
  mixins: [commonMixin],
  data() {
    return {
      config: {
        templateUrl: '', // URL tải mẫu
        importEndpoint: '' // API endpoint nhập file
      },
      selectedFiles: [], // Danh sách file đã chọn
      showDialog: false,
      requestHeaders: {
        'Content-Type': 'multipart/form-data'
      },
      isUploading: false,
      uploadUrl: '',
      fileToUpload: null // File sẽ được tải lên
    }
  },
  created() {
    this.setupComponent()
  },
  methods: {
    setupComponent() {
      this.config = initializeData(this.config, this.meta)
      this.children = initializeChildren(this.children, this.componentData)
    },
    handleFileRemove(file, fileList) {
      console.log('File removed:', file, fileList)
    },
    handlePreview(file) {
      console.log('File preview:', file)
    },
    handleUploadError(err, file, fileList) {
      console.error('Upload error:', err)
      this.$message.error('Nhập file thất bại')
    },
    handleUploadSuccess(response, file, fileList) {
      console.log('Server response:', response.data.jsonmsg.ERRORMSG)
      if (response.data.jsonmsg.ERRORMSG === '') {
        this.$message({
          message: 'Nhập dữ liệu thành công',
          type: 'success'
        })
        this.setupComponent()
        this.showDialog = false
      } else {
        const errorMsg = response.data.jsonmsg.ERRORMSG.slice(
          response.data.jsonmsg.ERRORMSG.indexOf('=') + 1
        )
        this.$message({
          message: errorMsg,
          type: 'error'
        })
      }
    },
    downloadTemplate() { // Tải mẫu nhập liệu
      window.location.href = process.env.VUE_APP_API_BASE + this.config.templateUrl
      // process.env.VUE_APP_API_BASE: Địa chỉ cơ sở (từ file môi trường)
    },
    // Mở dialog nhập file
    openImportDialog() {
      this.showDialog = true
      this.uploadUrl = process.env.VUE_APP_API_BASE + this.config.importEndpoint
      // Quan trọng: phải gán giá trị này cho uploadUrl
    },
    onFileChange(file) {
      this.fileToUpload = file.raw // Lưu file khi người dùng chọn
    },
    // Xử lý tải lên file
    customUpload(params) {
      if (this.fileToUpload) {
        const formData = new FormData() // Tạo đối tượng FormData
        this.fileToUpload = params.file 
        // Phải là params.file, dữ liệu gửi đến server sẽ là file:(binary)
        // Không phải this.fileToUpload, nếu không sẽ gửi file:Undefined
        
        formData.append('file', this.fileToUpload)
        
        sendFile({
          url: process.env.VUE_APP_API_BASE + this.config.importEndpoint,
          params: formData // Tham số phải là formData
        }).then(response => {
          console.log('Kết quả nhập:', response)
          if (response.statusCode === 200) {
            this.$notify({
              message: 'Nhập dữ liệu thành công',
              type: 'success'
            })
            this.showDialog = false
            eventBus.$emit('refreshData')
          } else {
            this.$notify.error('Nhập dữ liệu thất bại')
          }
        })
      }
    },
    submitFile() {
      this.$refs[this.uploadRef].submit() // Kích hoạt tải lên
    },
    cancelImport() {
      this.showDialog = false
      this.$message.info('Đã hủy thao tác tải lên')
    }
  }
}
</script>

Định nghĩa API:

export function sendFile(obj) {
  return request({
    url: obj.url,
    method: 'post',
    data: obj.params
  })
}

Lưu ý quan trọng: Header yêu cầu phải là: Content-Type: multipart/form-data; nếu không việc nhập file sẽ thất bại. Tham số truyền đi phải là đối tượng FormData.

Thẻ: Element UI Vue.js Excel import file upload FormData

Đăng vào ngày 18 tháng 8 lúc 05:35