| | |
| | | > |
| | | <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> |
| | |
| | | </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> |
| | |
| | | <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: { |
| | |
| | | required: true |
| | | }, |
| | | disabled: { |
| | | type: Boolean, |
| | | default: false |
| | | }, |
| | | autoUpload: { |
| | | type: Boolean, |
| | | default: false |
| | | }, |
| | |
| | | }) |
| | | |
| | | 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 = () => { |
| | |
| | | emit('download-template') |
| | | } |
| | | |
| | | const clearFiles = () => { |
| | | if (uploadRef.value) { |
| | | uploadRef.value.clearFiles() |
| | | } |
| | | } |
| | | |
| | | defineExpose({ |
| | | uploadRef, |
| | | submit, |
| | | clearFiles: () => { |
| | | if (uploadRef.value) { |
| | | uploadRef.value.clearFiles() |
| | | } |
| | | } |
| | | clearFiles |
| | | }) |
| | | </script> |
| | | |
| | |
| | | text-align: center; |
| | | } |
| | | </style> |
| | | |