You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
184 lines
5.2 KiB
184 lines
5.2 KiB
|
3 weeks ago
|
<template>
|
||
|
|
<div class="upload-file">
|
||
|
|
<el-upload
|
||
|
|
:action="uploadFileUrl"
|
||
|
|
:before-upload="handleBeforeUpload"
|
||
|
|
:file-list="fileList"
|
||
|
|
:limit="limit"
|
||
|
|
:on-error="handleUploadError"
|
||
|
|
:on-exceed="handleExceed"
|
||
|
|
:on-success="handleUploadSuccess"
|
||
|
|
:show-file-list="false"
|
||
|
|
:headers="headers"
|
||
|
|
class="upload-file-uploader"
|
||
|
|
ref="uploadRef"
|
||
|
|
>
|
||
|
|
<el-button type="primary" size="small">选取文件</el-button>
|
||
|
|
<template #tip>
|
||
|
|
<div class="el-upload__tip" v-if="showTip">
|
||
|
|
请上传
|
||
|
|
<template v-if="fileSize"> 大小不超过 <b class="danger-text">{{ fileSize }}MB</b> </template>
|
||
|
|
<template v-if="fileType.length"> 格式为 <b class="danger-text">{{ fileType.join('/') }}</b> </template>
|
||
|
|
的文件
|
||
|
|
</div>
|
||
|
|
</template>
|
||
|
|
</el-upload>
|
||
|
|
|
||
|
|
<transition-group class="upload-file-list el-upload-list el-upload-list--text" name="el-fade-in-linear" tag="ul">
|
||
|
|
<li :key="file.uid" class="el-upload-list__item ele-upload-list__item-content" v-for="file in fileList">
|
||
|
|
<el-link :href="`${baseUrl}${file.url}`" :underline="false" target="_blank">
|
||
|
|
<el-icon><Document /></el-icon> {{ getFileName(file.name) }}
|
||
|
|
</el-link>
|
||
|
|
<div class="ele-upload-list__item-content-action">
|
||
|
|
<el-link :underline="false" @click="handleDelete(fileList.indexOf(file))" type="danger">删除</el-link>
|
||
|
|
</div>
|
||
|
|
</li>
|
||
|
|
</transition-group>
|
||
|
|
</div>
|
||
|
|
</template>
|
||
|
|
|
||
|
|
<script setup lang="ts">
|
||
|
|
import { ref, computed, watch } from 'vue'
|
||
|
|
import { Document } from '@element-plus/icons-vue'
|
||
|
|
import { ElMessage } from 'element-plus'
|
||
|
|
import { getToken } from '@/utils/auth'
|
||
|
|
import type { UploadFileItem } from '@/types'
|
||
|
|
|
||
|
|
interface Props {
|
||
|
|
modelValue?: string | UploadFileItem | UploadFileItem[]
|
||
|
|
limit?: number
|
||
|
|
fileSize?: number
|
||
|
|
fileType?: string[]
|
||
|
|
isShowTip?: boolean
|
||
|
|
}
|
||
|
|
|
||
|
|
const props = withDefaults(defineProps<Props>(), {
|
||
|
|
modelValue: '',
|
||
|
|
limit: 5,
|
||
|
|
fileSize: 5,
|
||
|
|
fileType: () => ['doc', 'xls', 'ppt', 'txt', 'pdf'],
|
||
|
|
isShowTip: true
|
||
|
|
})
|
||
|
|
|
||
|
|
const emit = defineEmits<{
|
||
|
|
'update:modelValue': [value: string]
|
||
|
|
}>()
|
||
|
|
|
||
|
|
const baseUrl = import.meta.env.VITE_APP_BASE_API || ''
|
||
|
|
const uploadFileUrl = `${import.meta.env.VITE_APP_BASE_API}/common/upload`
|
||
|
|
const headers = {
|
||
|
|
Authorization: `Bearer ${getToken()}`
|
||
|
|
}
|
||
|
|
const fileList = ref<UploadFileItem[]>([])
|
||
|
|
|
||
|
|
const showTip = computed(() => props.isShowTip && (props.fileType.length > 0 || props.fileSize > 0))
|
||
|
|
|
||
|
|
function handleBeforeUpload(file: File): boolean {
|
||
|
|
// Check file type
|
||
|
|
if (props.fileType.length > 0) {
|
||
|
|
let fileExtension = ''
|
||
|
|
const lastDotIndex = file.name.lastIndexOf('.')
|
||
|
|
if (lastDotIndex > -1) {
|
||
|
|
fileExtension = file.name.slice(lastDotIndex + 1)
|
||
|
|
}
|
||
|
|
const isTypeOk = props.fileType.some(type => {
|
||
|
|
if (file.type.indexOf(type) > -1) return true
|
||
|
|
if (fileExtension && fileExtension.indexOf(type) > -1) return true
|
||
|
|
return false
|
||
|
|
})
|
||
|
|
if (!isTypeOk) {
|
||
|
|
ElMessage.error(`文件格式不正确, 请上传${props.fileType.join('/')}格式文件!`)
|
||
|
|
return false
|
||
|
|
}
|
||
|
|
}
|
||
|
|
// Check file size
|
||
|
|
if (props.fileSize) {
|
||
|
|
const isLt = file.size / 1024 / 1024 < props.fileSize
|
||
|
|
if (!isLt) {
|
||
|
|
ElMessage.error(`上传文件大小不能超过 ${props.fileSize} MB!`)
|
||
|
|
return false
|
||
|
|
}
|
||
|
|
}
|
||
|
|
return true
|
||
|
|
}
|
||
|
|
|
||
|
|
function handleExceed() {
|
||
|
|
ElMessage.error(`上传文件数量不能超过 ${props.limit} 个!`)
|
||
|
|
}
|
||
|
|
|
||
|
|
function handleUploadError() {
|
||
|
|
ElMessage.error('上传失败, 请重试')
|
||
|
|
}
|
||
|
|
|
||
|
|
function handleUploadSuccess(res: { fileName: string }) {
|
||
|
|
ElMessage.success('上传成功')
|
||
|
|
fileList.value.push({ name: res.fileName, url: res.fileName })
|
||
|
|
emit('update:modelValue', listToString(fileList.value))
|
||
|
|
}
|
||
|
|
|
||
|
|
function handleDelete(index: number) {
|
||
|
|
fileList.value.splice(index, 1)
|
||
|
|
emit('update:modelValue', listToString(fileList.value))
|
||
|
|
}
|
||
|
|
|
||
|
|
function getFileName(name: string): string {
|
||
|
|
const lastSlashIndex = name.lastIndexOf('/')
|
||
|
|
if (lastSlashIndex > -1) {
|
||
|
|
return name.slice(lastSlashIndex + 1).toLowerCase()
|
||
|
|
}
|
||
|
|
return name.toLowerCase()
|
||
|
|
}
|
||
|
|
|
||
|
|
function listToString(list: UploadFileItem[], separator = ','): string {
|
||
|
|
const urls = list.map(item => item.url)
|
||
|
|
return urls.join(separator)
|
||
|
|
}
|
||
|
|
|
||
|
|
watch(
|
||
|
|
() => props.modelValue,
|
||
|
|
(val) => {
|
||
|
|
if (val) {
|
||
|
|
let temp = 1
|
||
|
|
const list = Array.isArray(val) ? val : String(val).split(',')
|
||
|
|
fileList.value = list.map(item => {
|
||
|
|
if (typeof item === 'string') {
|
||
|
|
return { name: item, url: item, uid: new Date().getTime() + temp++ }
|
||
|
|
}
|
||
|
|
return { ...item, uid: (item as UploadFileItem).uid || new Date().getTime() + temp++ } as UploadFileItem
|
||
|
|
})
|
||
|
|
} else {
|
||
|
|
fileList.value = []
|
||
|
|
}
|
||
|
|
},
|
||
|
|
{ deep: true, immediate: true }
|
||
|
|
)
|
||
|
|
</script>
|
||
|
|
|
||
|
|
<style scoped lang="scss">
|
||
|
|
.upload-file-uploader {
|
||
|
|
margin-bottom: 5px;
|
||
|
|
}
|
||
|
|
|
||
|
|
.upload-file-list .el-upload-list__item {
|
||
|
|
border: 1px solid #e4e7ed;
|
||
|
|
line-height: 2;
|
||
|
|
margin-bottom: 10px;
|
||
|
|
position: relative;
|
||
|
|
}
|
||
|
|
|
||
|
|
.upload-file-list .ele-upload-list__item-content {
|
||
|
|
display: flex;
|
||
|
|
justify-content: space-between;
|
||
|
|
align-items: center;
|
||
|
|
color: inherit;
|
||
|
|
}
|
||
|
|
|
||
|
|
.ele-upload-list__item-content-action .el-link {
|
||
|
|
margin-right: 10px;
|
||
|
|
}
|
||
|
|
|
||
|
|
.danger-text {
|
||
|
|
color: #f56c6c;
|
||
|
|
}
|
||
|
|
</style>
|