1. 效果图
2. 组件完整代码
< template>
< div class = " custom-import-warpper" >
< el-dialog v-model = " dialogVisible" :title = " dialogTitle" width = " 600px" :close-on-click-modal = " false" >
< el-form label-width = " 140px" >
< el-form-item label = " 点击下载模板" >
< el-link type = " primary" :underline = " false" @click = " downloadTemp" > 下载模板</ el-link>
</ el-form-item>
< el-form-item label = " 选择导入模板" required style = " margin-bottom : 0" >
< el-upload style = " width : 100%" :file-list = " fileList" :accept = " fileTypes" :auto-upload = " false" :on-change = " handleChange" >
< el-button type = " primary" v-out > 选择文件</ el-button>
</ el-upload>
</ el-form-item>
< el-form-item>
< div class = " tips" >
< div> 提示:</ div>
< div> · 表格格式需要正确正确</ div>
< div> · 数据不能为空,否则存在导入失败</ div>
</ div>
</ el-form-item>
< el-form-item label = " 点击下载错误文件" v-if = " errorUrl && fileList.length > 0" >
< el-link type = " primary" :underline = " false" @click = " downloadError" > 下载错误文件</ el-link>
</ el-form-item>
</ el-form>
< template #footer >
< el-button @click = " onReset" > 取消</ el-button>
< el-button @click = " onSubmit" :loading = " submitLoading" type = " primary" v-out > 确定</ el-button>
</ template>
</ el-dialog>
< el-dialog v-model = " dialogErrorVisible" :title = " `${dialogTitle}失败数据`" width = " 800px" :close-on-click-modal = " false" >
< slot :tableData = " tableData" > </ slot>
< template #footer >
< el-button @click = " dialogErrorVisible = false" > 关闭</ el-button>
< el-button @click = " downloadError" type = " primary" v-out > 导出失败数据</ el-button>
</ template>
</ el-dialog>
</ div>
</ template>
< script setup lang = " ts" name = " CustomImport" >
import axios from 'axios'
import { ElMessage } from 'element-plus'
import type { UploadProps, UploadUserFile } from 'element-plus'
import { onMounted, ref, reactive, toRefs } from 'vue'
import { globalUrl } from '@/utils/global'
import { downloadFile } from '@/utils/tool'
const props = defineProps ( {
limit : {
type : Number,
default : null
} ,
size : {
type : Number,
default : null
} ,
title : {
type : String,
default : '导入文件'
} ,
fileTypes : {
type : String,
default : '.xls,.xlsx'
} ,
prefix : {
type : String,
default : 'electronic'
} ,
actionUrl : {
type : String,
default : ''
} ,
templateUrl : {
type : String,
default : ''
} ,
errorUrl : {
type : String,
default : ''
} ,
fileDownType : {
type : String,
default : ''
}
} )
const token = ref< any> ( localStorage. getItem ( 'pc/token' ) )
const env = import . meta. env
const baseURL = ref< string> ( '' )
const submitLoading = ref< boolean> ( false )
const dialogVisible = ref< boolean> ( false )
const errorUrl = ref< string> ( '' )
const dialogTitle = ref< string> ( props. title)
const dialogErrorVisible = ref< boolean> ( false )
const state = reactive ( {
fileList : [ ] as Array< UploadUserFile> ,
tableData : [ ] as Array< any>
} )
const { fileList, tableData } = toRefs ( state)
const show = ( ) => {
dialogVisible. value = true
state. fileList = [ ]
errorUrl. value = ''
baseURL. value = globalUrl[ env. MODE ] + props. prefix
}
defineExpose ( { show } )
const emits = defineEmits< {
( e: 'success' ) : void
} > ( )
onMounted ( ( ) => { } )
const downloadTemp = ( ) => {
if ( props. fileDownType == 'flow' ) {
downTempByFlow ( )
} else {
downTempByUrl ( )
}
}
const downTempByFlow = ( ) => {
axios ( {
method : 'get' ,
url : ` ${ baseURL. value} ${ props. templateUrl} ` ,
responseType : 'blob' ,
headers : {
Authorization : token. value,
'content-type' : 'application/x-www-form-urlencoded'
}
} ) . then ( res => {
if ( ! res) {
ElMessage. error ( '系统错误' )
} else {
downloadFile ( res, ` ${ dialogTitle. value} 模板.xlsx ` )
}
} )
}
const downTempByUrl = ( ) => {
axios
. get ( ` ${ baseURL. value} ${ props. templateUrl} ` , {
headers : {
Authorization : token. value,
'content-type' : 'application/x-www-form-urlencoded'
}
} )
. then ( res => {
const { code, data, message } = res. data
if ( code == '00000' ) {
window. location. href = data
} else {
ElMessage. error ( message || '系统错误' )
}
} )
. catch ( e => { } )
}
const downloadError = ( ) => {
if ( props. fileDownType == 'flow' ) {
downErroeByFlow ( )
} else {
window. location. href = errorUrl. value
}
}
const downErroeByFlow = ( ) => {
axios ( {
method : 'post' ,
url : ` ${ baseURL. value} ${ props. errorUrl} ` ,
responseType : 'blob' ,
data : state. tableData,
headers : {
Authorization : token. value
}
} ) . then ( res => {
if ( ! res) {
ElMessage. error ( '系统错误' )
} else {
downloadFile ( res, ` ${ dialogTitle. value} 错误文件.xlsx ` )
}
} )
}
const handleChange : UploadProps[ 'onChange' ] = ( uploadFile, uploadFiles ) => {
state. fileList = [ { ... uploadFile } ]
errorUrl. value = ''
}
const onReset = ( ) => {
dialogVisible. value = false
state. fileList = [ ]
}
const onSubmit = ( ) => {
if ( state. fileList. length < 1 ) {
ElMessage. warning ( '请选择导入模板' )
return
}
if ( submitLoading. value) {
return
}
submitLoading. value = true
let formdata = new FormData ( )
formdata. append ( 'file' , state. fileList[ 0 ] . raw)
axios ( {
method : 'post' ,
url : ` ${ baseURL. value} ${ props. actionUrl} ` ,
data : formdata,
headers : {
Authorization : token. value
}
} )
. then ( res => {
let { code, message, data } = res. data
submitLoading. value = false
if ( code !== '00000' ) {
ElMessage. error ( message || '模板错误' )
} else {
if ( ! data || ( data && data. length < 1 ) ) {
ElMessage. success ( '导入成功' )
errorUrl. value = ''
onReset ( )
} else {
if ( typeof data == 'string' ) {
errorUrl. value = data
} else if ( data && data. length > 0 ) {
state. tableData = data
dialogErrorVisible. value = true
dialogVisible. value = false
}
}
emits ( 'success' )
}
} )
. catch ( e => {
submitLoading. value = false
} )
}
</ script>
< style lang = " scss" scoped >
.tips {
font-weight : 400;
font-size : 12px;
color : #86909c;
line-height : 20px;
}
</ style>
3. 组件使用示例
< CustomImport
ref = " batchImportRef"
fileDownType = " flow"
prefix = " finance"
title = " 批量导入"
actionUrl = " /api/point/uploadDetail"
errorUrl = " /api/point/exportErrors"
templateUrl = " /api/point/downloadTemplate"
@success = " searchHandle(pagination)"
> </ CustomImport>
const batchImportRef = ref ( )
const handleImport = ( ) => {
batchImportRef. value. show ( )
}