123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250 |
- <template>
- <div class="upload-file">
- <el-upload
- ref="uploadRef"
- :action="uploadFileUrl"
- :file-list="_fileList"
- class="upload-file-uploader"
- :show-file-list="false"
- :multiple="true"
- :disabled="self_disabled"
- :limit="limit"
- :before-upload="beforeUpload"
- :on-exceed="handleExceed"
- :on-success="uploadSuccess"
- :on-error="uploadError"
- :accept="fileType.join(',')"
- :headers="headers"
- >
- <el-button :icon="icon" type="primary">{{ text }}</el-button>
- </el-upload>
- <!-- 上传提示 -->
- <div class="el-upload__tip" v-if="showTip">
- 请上传
- <template v-if="fileSize">
- 大小不超过 <b style="color: #f56c6c">{{ fileSize }}MB</b>
- </template>
- <template v-if="fileType">
- 格式为 <b style="color: #f56c6c">{{ fileType.join('/') }}</b>
- </template>
- 的文件
- </div>
- <!-- 文件列表 -->
- <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, index) in _fileList">
- <el-link :href="`${file.url}`" :underline="false" target="_blank">
- <span class="document">
- {{ file.name }}
- </span>
- </el-link>
- <div class="ele-upload-list__item-content-action">
- <el-link :underline="false" @click="handleRemove(index)" type="danger">删除</el-link>
- </div>
- </li>
- </transition-group>
- </div>
- </template>
- <script setup lang="ts" name="UploadImgs">
- import { ref, computed, inject, watch } from 'vue'
- import type { UploadProps, UploadFile } from 'element-plus'
- import { ElMessage, formContextKey, formItemContextKey, UploadInstance } from 'element-plus'
- import { showFullScreenLoading, tryHideFullScreenLoading } from '@/components/Loading/fullScreen'
- import { globalHeaders } from '@/api'
- import { OssVO } from '@/api/interface/system/oss'
- import { getListByIdsApi, delOssApi } from '@/api/modules/system/oss'
- import { listToString } from '@/utils/common'
- interface UploadFileProps {
- modelValue?: string | number
- disabled?: boolean // 是否禁用上传组件 ==> 非必传(默认为 false)
- drag?: boolean // 是否支持拖拽上传 ==> 非必传(默认为 true)
- limit?: number // 最大图片上传数 ==> 非必传(默认为 5张)
- fileSize?: number // 图片大小限制 ==> 非必传(默认为 5M)
- isShowTip?: boolean // 是否显示提示信息 ==> 非必传(默认为 true)
- text?: string // 按钮文字
- icon?: string
- fileType?: Array<string>
- uploadApiPath?: string // 上传文件服务器地址
- }
- // 默认值
- const props = withDefaults(defineProps<UploadFileProps>(), {
- modelValue: () => '',
- drag: true,
- disabled: false,
- limit: 1,
- fileSize: 5,
- fileType: () => ['doc', 'docx', 'xls', 'xlsx', 'ppt', 'txt', 'pdf', 'mp4'],
- text: '文件上传',
- isShowTip: true,
- uploadApiPath: '/common/upload',
- icon: 'upload-filled'
- })
- const baseUrl = import.meta.env.VITE_API_URL
- const uploadFileUrl = ref(baseUrl + props.uploadApiPath)
- const headers = ref(globalHeaders())
- const uploadRef = ref<UploadInstance>()
- const number = ref(0)
- const showTip = computed(() => props.isShowTip && (props.fileType || props.fileSize))
- const uploadList = ref<any[]>([])
- const uploadFileListExport = ref<any[]>([])
- const emit = defineEmits<{
- 'update:modelValue': [value: any]
- }>()
- // 获取 el-form 组件上下文
- const formContext = inject(formContextKey, void 0)
- // 获取 el-form-item 组件上下文
- const formItemContext = inject(formItemContextKey, void 0)
- // 判断是否禁用上传和删除
- const self_disabled = computed(() => {
- return props.disabled || formContext?.disabled
- })
- const _fileList = ref<any[]>([])
- // 监听 props.modelValue 列表默认值改变
- watch(
- () => props.modelValue,
- async (val: string | number) => {
- if (val) {
- let temp = 1
- // 首先将值转为数组
- let list: any[] = []
- if (Array.isArray(val)) {
- list = val as OssVO[]
- } else {
- const res = await getListByIdsApi(val)
- list = res.data.map(oss => {
- return {
- name: oss.originalName,
- url: oss.url,
- ossId: oss.ossId
- }
- })
- }
- // 然后将数组转为对象数组
- _fileList.value = list.map(item => {
- item = { name: item.name, url: item.url, ossId: item.ossId }
- item.uid = item.uid || new Date().getTime() + temp++
- return item
- })
- } else {
- _fileList.value = []
- return []
- }
- },
- { deep: true, immediate: true }
- )
- /**
- * @description 文件上传之前判断
- * @param rawFile 选择的文件
- * */
- const beforeUpload: UploadProps['beforeUpload'] = rawFile => {
- // 校验文件格式
- const fileName = rawFile.name.split('.')
- const fileExt = fileName[fileName.length - 1]
- const isTypeOk = props.fileType.indexOf(fileExt) >= 0
- // 校检文件大小
- const isLt = rawFile.size / 1024 / 1024 < props.fileSize
- if (!isTypeOk) {
- ElMessage.error(`文件格式不正确, 请上传${props.fileType.join('/')}格式文件!`)
- return false
- }
- if (!isLt) {
- ElMessage.error(`文件大小不能超过 ${props.fileSize}M!`)
- return false
- }
- number.value++
- showFullScreenLoading('正在上传文件,请稍候...')
- return isTypeOk && isLt
- }
- /**
- * @description 文件上传成功
- * @param response 上传响应结果
- * @param uploadFile 上传的文件
- * */
- const uploadSuccess = (response: any | undefined, uploadFile: UploadFile) => {
- if (response.code !== 200) {
- number.value--
- ElMessage.error(response.msg)
- uploadRef.value?.handleRemove(uploadFile)
- uploadedSuccessfully()
- return
- }
- uploadList.value.push({ name: response.data.fileName, url: response.data.url, ossId: response.data.ossId })
- uploadFileListExport.value = []
- uploadFileListExport.value.push({ name: response.data.fileName, url: response.data.url, ossId: response.data.ossId })
- console.log(uploadList.value)
- uploadedSuccessfully()
- }
- // 上传结束处理
- const uploadedSuccessfully = () => {
- if (number.value > 0 && uploadList.value.length === number.value) {
- _fileList.value = _fileList.value.filter(f => f.url !== undefined).concat(uploadList.value)
- uploadList.value = []
- number.value = 0
- console.log('update', listToString(_fileList.value))
- emit('update:modelValue', listToString(_fileList.value))
- tryHideFullScreenLoading()
- }
- // 监听表单验证
- formItemContext?.prop && formContext?.validateField([formItemContext.prop as string])
- }
- /**
- * @description 删除图片
- * @param file 删除的文件
- * */
- const handleRemove = (index: number) => {
- let ossId = _fileList.value[index].ossId
- delOssApi(ossId)
- _fileList.value.splice(index, 1)
- emit('update:modelValue', listToString(_fileList.value))
- }
- /**
- * @description 文件上传错误
- * */
- const uploadError = () => {
- ElMessage.error('文件上传失败,请您重新上传!')
- }
- /**
- * @description 文件数超出
- * */
- const handleExceed = () => {
- ElMessage.warning(`当前最多只能上传 ${props.limit} 个文件 ,请移除后上传!`)
- }
- defineExpose({
- uploadFileListExport
- })
- </script>
- <style scoped lang="scss">
- .upload-file-uploader {
- margin-bottom: 5px;
- }
- .upload-file-list .el-upload-list__item {
- position: relative;
- margin-bottom: 10px;
- line-height: 2;
- border: 1px solid #e4e7ed;
- }
- .upload-file-list .ele-upload-list__item-content {
- display: flex;
- align-items: center;
- justify-content: space-between;
- color: inherit;
- }
- .ele-upload-list__item-content-action .el-link {
- margin-right: 10px;
- }
- </style>
|