gaoluyang
2 天以前 801a3bc53415f6214800c561a562d17ea58b88f1
src/components/Dialog/ImportDialog.vue
@@ -8,17 +8,16 @@
  >
    <el-upload
      ref="uploadRef"
      v-model:file-list="fileList"
      :limit="limit"
      :accept="accept"
      :headers="headers"
      :action="action"
      :disabled="disabled"
      :before-upload="beforeUpload"
      :on-progress="onProgress"
      :on-success="onSuccess"
      :on-error="onError"
      :on-change="onChange"
      :auto-upload="autoUpload"
      :http-request="handleHttpRequest"
      :on-change="onChange || (() => {})"
      :auto-upload="false"
      drag
    >
      <el-icon class="el-icon--upload"><UploadFilled /></el-icon>
@@ -39,7 +38,7 @@
    </el-upload>
    <template #footer>
      <div class="dialog-footer">
        <el-button type="primary" @click="handleConfirm">确 定</el-button>
        <el-button type="primary" @click="handleConfirm" :loading="uploading">确 定</el-button>
        <el-button @click="handleCancel">取 消</el-button>
      </div>
    </template>
@@ -49,6 +48,9 @@
<script setup>
import { computed, ref } from 'vue'
import { UploadFilled } from '@element-plus/icons-vue'
import axios from 'axios'
import { getToken } from '@/utils/auth'
import { ElMessage } from 'element-plus'
const props = defineProps({
  modelValue: {
@@ -84,10 +86,6 @@
    required: true
  },
  disabled: {
    type: Boolean,
    default: false
  },
  autoUpload: {
    type: Boolean,
    default: false
  },
@@ -129,19 +127,96 @@
})
const uploadRef = ref(null)
const fileList = ref([])
const uploading = ref(false)
const handleClose = () => {
  emit('close')
}
const handleConfirm = () => {
  emit('confirm')
const handleHttpRequest = async (options) => {
  const { file, onProgress, onSuccess, onError } = options
  uploading.value = true
  const formData = new FormData()
  formData.append('file', file)
  try {
    const response = await axios({
      url: props.action,
      method: 'post',
      data: formData,
      headers: {
        'Authorization': 'Bearer ' + getToken(),
        ...props.headers,
        'Content-Type': 'multipart/form-data'
      },
      responseType: 'blob',
      onUploadProgress: (progressEvent) => {
        const percent = Math.round((progressEvent.loaded * 100) / progressEvent.total)
        if (onProgress) {
          onProgress({ percent })
        }
        if (props.onProgress) {
          props.onProgress({ percent }, file)
        }
      }
    })
    uploading.value = false
    const blob = response.data
    // 先尝试将 blob 解析为 JSON(无论 content-type 是什么)
    try {
      const text = await blob.text()
      const jsonResponse = JSON.parse(text)
      // 成功解析为 JSON
      if (jsonResponse.code === 200) {
        if (onSuccess) onSuccess(jsonResponse)
        if (props.onSuccess) props.onSuccess(jsonResponse, file)
      } else {
        const error = new Error(jsonResponse.msg || '导入失败')
        error.response = { data: jsonResponse }
        if (onError) onError(error)
        if (props.onError) props.onError(jsonResponse, file)
      }
    } catch (e) {
      // 不是 JSON,是文件流,下载错误文件
      downloadBlob(blob, '导入错误数据.xlsx')
      if (onError) {
        const error = new Error('导入失败,请查看下载的错误文件')
        error.response = { data: blob }
        onError(error)
      }
      if (props.onError) {
        props.onError(blob, file)
      }
    }
  } catch (error) {
    uploading.value = false
    if (options.onError) options.onError(error)
    if (props.onError) props.onError(error, file)
  }
}
const submit = () => {
  if (uploadRef.value) {
    uploadRef.value.submit()
const downloadBlob = (blob, filename) => {
  const downloadElement = document.createElement('a')
  const href = window.URL.createObjectURL(blob)
  downloadElement.href = href
  downloadElement.download = filename
  document.body.appendChild(downloadElement)
  downloadElement.click()
  document.body.removeChild(downloadElement)
  window.URL.revokeObjectURL(href)
}
const handleConfirm = () => {
  if (!fileList.value || fileList.value.length === 0) {
    ElMessage.warning('请选择文件')
    return
  }
  uploadRef.value.submit()
}
const handleCancel = () => {
@@ -153,14 +228,15 @@
  emit('download-template')
}
const clearFiles = () => {
  if (uploadRef.value) {
    uploadRef.value.clearFiles()
  }
}
defineExpose({
  uploadRef,
  submit,
  clearFiles: () => {
    if (uploadRef.value) {
      uploadRef.value.clearFiles()
    }
  }
  clearFiles
})
</script>
@@ -169,4 +245,3 @@
  text-align: center;
}
</style>