|
@@ -3,7 +3,7 @@
|
|
<el-upload
|
|
<el-upload
|
|
ref="uploadRef"
|
|
ref="uploadRef"
|
|
:action="uploadFileUrl"
|
|
:action="uploadFileUrl"
|
|
- v-model:file-list="_fileList"
|
|
|
|
|
|
+ :file-list="_fileList"
|
|
class="upload-file-uploader"
|
|
class="upload-file-uploader"
|
|
:show-file-list="false"
|
|
:show-file-list="false"
|
|
:multiple="true"
|
|
:multiple="true"
|
|
@@ -16,7 +16,7 @@
|
|
:accept="fileType.join(',')"
|
|
:accept="fileType.join(',')"
|
|
:headers="headers"
|
|
:headers="headers"
|
|
>
|
|
>
|
|
- <el-button :icon="icon" type="primary">{{ text }}</el-button>
|
|
|
|
|
|
+ <el-button icon="icon" type="primary">{{ text }}</el-button>
|
|
</el-upload>
|
|
</el-upload>
|
|
<!-- 上传提示 -->
|
|
<!-- 上传提示 -->
|
|
<div class="el-upload__tip" v-if="showTip">
|
|
<div class="el-upload__tip" v-if="showTip">
|
|
@@ -32,9 +32,9 @@
|
|
<!-- 文件列表 -->
|
|
<!-- 文件列表 -->
|
|
<transition-group class="upload-file-list el-upload-list el-upload-list--text" name="el-fade-in-linear" tag="ul">
|
|
<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">
|
|
<li :key="file.uid" class="el-upload-list__item ele-upload-list__item-content" v-for="(file, index) in _fileList">
|
|
- <el-link :href="`${baseUrl}${file.url}`" :underline="false" target="_blank">
|
|
|
|
|
|
+ <el-link :href="`${file.url}`" :underline="false" target="_blank">
|
|
<span class="document">
|
|
<span class="document">
|
|
- {{ getFileName(file.name) }}
|
|
|
|
|
|
+ {{ file.name }}
|
|
</span>
|
|
</span>
|
|
</el-link>
|
|
</el-link>
|
|
<div class="ele-upload-list__item-content-action">
|
|
<div class="ele-upload-list__item-content-action">
|
|
@@ -47,47 +47,47 @@
|
|
|
|
|
|
<script setup lang="ts" name="UploadImgs">
|
|
<script setup lang="ts" name="UploadImgs">
|
|
import { ref, computed, inject, watch } from 'vue'
|
|
import { ref, computed, inject, watch } from 'vue'
|
|
-import type { UploadProps, UploadFile, UploadUserFile } from 'element-plus'
|
|
|
|
-import { ElNotification, ElMessage, formContextKey, formItemContextKey, UploadInstance } from 'element-plus'
|
|
|
|
-import { getToken } from '@/utils/token'
|
|
|
|
|
|
+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 {
|
|
interface UploadFileProps {
|
|
- modelValue?: any
|
|
|
|
|
|
+ modelValue?: string | number
|
|
disabled?: boolean // 是否禁用上传组件 ==> 非必传(默认为 false)
|
|
disabled?: boolean // 是否禁用上传组件 ==> 非必传(默认为 false)
|
|
drag?: boolean // 是否支持拖拽上传 ==> 非必传(默认为 true)
|
|
drag?: boolean // 是否支持拖拽上传 ==> 非必传(默认为 true)
|
|
limit?: number // 最大图片上传数 ==> 非必传(默认为 5张)
|
|
limit?: number // 最大图片上传数 ==> 非必传(默认为 5张)
|
|
fileSize?: number // 图片大小限制 ==> 非必传(默认为 5M)
|
|
fileSize?: number // 图片大小限制 ==> 非必传(默认为 5M)
|
|
- height?: string // 组件高度 ==> 非必传(默认为 150px)
|
|
|
|
- width?: string // 组件宽度 ==> 非必传(默认为 150px)
|
|
|
|
- borderRadius?: string // 组件边框圆角 ==> 非必传(默认为 8px)
|
|
|
|
isShowTip?: boolean // 是否显示提示信息 ==> 非必传(默认为 true)
|
|
isShowTip?: boolean // 是否显示提示信息 ==> 非必传(默认为 true)
|
|
text?: string // 按钮文字
|
|
text?: string // 按钮文字
|
|
icon?: string
|
|
icon?: string
|
|
- fileList?: UploadUserFile[]
|
|
|
|
- fileType?: Array<any>
|
|
|
|
|
|
+ fileType?: Array<string>
|
|
}
|
|
}
|
|
-// const emit = defineEmits(['update:modelValue'])
|
|
|
|
-const emit = defineEmits<{
|
|
|
|
- 'update:modelValue': [value: any]
|
|
|
|
-}>()
|
|
|
|
-const baseUrl = import.meta.env.VITE_API_URL
|
|
|
|
-const uploadFileUrl = ref(import.meta.env.VITE_API_URL + '/common/upload') // 上传文件服务器地址
|
|
|
|
-const headers = ref({ Authorization: 'Bearer ' + getToken() })
|
|
|
|
-const uploadRef = ref<UploadInstance>()
|
|
|
|
-const showTip = computed(() => props.isShowTip && (props.fileType || props.fileSize))
|
|
|
|
|
|
+// 默认值
|
|
const props = withDefaults(defineProps<UploadFileProps>(), {
|
|
const props = withDefaults(defineProps<UploadFileProps>(), {
|
|
- fileList: () => [],
|
|
|
|
|
|
+ modelValue: () => '',
|
|
drag: true,
|
|
drag: true,
|
|
disabled: false,
|
|
disabled: false,
|
|
limit: 1,
|
|
limit: 1,
|
|
- fileSize: 500,
|
|
|
|
- fileType: () => ['doc', 'xls', 'xlsx', 'ppt', 'txt', 'pdf'],
|
|
|
|
- height: '150px',
|
|
|
|
- width: '150px',
|
|
|
|
- borderRadius: '8px',
|
|
|
|
|
|
+ fileSize: 5,
|
|
|
|
+ fileType: () => ['doc', 'docx', 'xls', 'xlsx', 'ppt', 'txt', 'pdf'],
|
|
text: '文件上传',
|
|
text: '文件上传',
|
|
- isShowTip: false
|
|
|
|
|
|
+ isShowTip: true
|
|
})
|
|
})
|
|
|
|
|
|
|
|
+const baseUrl = import.meta.env.VITE_API_URL
|
|
|
|
+const uploadFileUrl = ref(baseUrl + '/common/upload') // 上传文件服务器地址
|
|
|
|
+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 emit = defineEmits<{
|
|
|
|
+ 'update:modelValue': [value: any]
|
|
|
|
+}>()
|
|
|
|
+
|
|
// 获取 el-form 组件上下文
|
|
// 获取 el-form 组件上下文
|
|
const formContext = inject(formContextKey, void 0)
|
|
const formContext = inject(formContextKey, void 0)
|
|
// 获取 el-form-item 组件上下文
|
|
// 获取 el-form-item 组件上下文
|
|
@@ -97,25 +97,41 @@ const self_disabled = computed(() => {
|
|
return props.disabled || formContext?.disabled
|
|
return props.disabled || formContext?.disabled
|
|
})
|
|
})
|
|
|
|
|
|
-const _fileList = ref<UploadUserFile[]>(props.fileList)
|
|
|
|
|
|
+const _fileList = ref<any[]>([])
|
|
|
|
|
|
-// 获取文件名称
|
|
|
|
-const getFileName = name => {
|
|
|
|
- if (name.lastIndexOf('/') > -1) {
|
|
|
|
- return name.slice(name.lastIndexOf('/') + 1)
|
|
|
|
- } else {
|
|
|
|
- return ''
|
|
|
|
- }
|
|
|
|
-}
|
|
|
|
-
|
|
|
|
-// 监听 props.fileList 列表默认值改变
|
|
|
|
|
|
+// 监听 props.modelValue 列表默认值改变
|
|
watch(
|
|
watch(
|
|
- () => props.fileList,
|
|
|
|
- (n: UploadUserFile[]) => {
|
|
|
|
- _fileList.value = n
|
|
|
|
- }
|
|
|
|
|
|
+ () => 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 文件上传之前判断
|
|
* @description 文件上传之前判断
|
|
* @param rawFile 选择的文件
|
|
* @param rawFile 选择的文件
|
|
@@ -127,21 +143,16 @@ const beforeUpload: UploadProps['beforeUpload'] = rawFile => {
|
|
const isTypeOk = props.fileType.indexOf(fileExt) >= 0
|
|
const isTypeOk = props.fileType.indexOf(fileExt) >= 0
|
|
// 校检文件大小
|
|
// 校检文件大小
|
|
const isLt = rawFile.size / 1024 / 1024 < props.fileSize
|
|
const isLt = rawFile.size / 1024 / 1024 < props.fileSize
|
|
-
|
|
|
|
- if (!isTypeOk)
|
|
|
|
- ElNotification({
|
|
|
|
- title: '温馨提示',
|
|
|
|
- message: '上传文件不符合所需的格式!',
|
|
|
|
- type: 'warning'
|
|
|
|
- })
|
|
|
|
- if (!isLt)
|
|
|
|
- setTimeout(() => {
|
|
|
|
- ElNotification({
|
|
|
|
- title: '温馨提示',
|
|
|
|
- message: `上传文件大小不能超过 ${props.fileSize}M!`,
|
|
|
|
- type: 'warning'
|
|
|
|
- })
|
|
|
|
- }, 0)
|
|
|
|
|
|
+ if (!isTypeOk) {
|
|
|
|
+ ElMessage.error(`文件格式不正确, 请上传${props.fileType.join('/')}格式文件!`)
|
|
|
|
+ return false
|
|
|
|
+ }
|
|
|
|
+ if (!isLt) {
|
|
|
|
+ ElMessage.error(`文件大小不能超过 ${props.fileSize}M!`)
|
|
|
|
+ return false
|
|
|
|
+ }
|
|
|
|
+ number.value++
|
|
|
|
+ showFullScreenLoading('正在上传文件,请稍候...')
|
|
return isTypeOk && isLt
|
|
return isTypeOk && isLt
|
|
}
|
|
}
|
|
|
|
|
|
@@ -151,28 +162,29 @@ const beforeUpload: UploadProps['beforeUpload'] = rawFile => {
|
|
* @param uploadFile 上传的文件
|
|
* @param uploadFile 上传的文件
|
|
* */
|
|
* */
|
|
const uploadSuccess = (response: any | undefined, uploadFile: UploadFile) => {
|
|
const uploadSuccess = (response: any | undefined, uploadFile: UploadFile) => {
|
|
- if (response.code === 200) {
|
|
|
|
- uploadFile.url = response.url
|
|
|
|
- uploadFile.name = response.fileName
|
|
|
|
- emit('update:modelValue', _fileList.value)
|
|
|
|
- // 调用 el-form 内部的校验方法(可自动校验)
|
|
|
|
- formItemContext?.prop && formContext?.validateField([formItemContext.prop as string])
|
|
|
|
- ElNotification({
|
|
|
|
- title: '温馨提示',
|
|
|
|
- message: '文件上传成功!',
|
|
|
|
- type: 'success'
|
|
|
|
- })
|
|
|
|
- } else {
|
|
|
|
|
|
+ if (response.code !== 200) {
|
|
|
|
+ number.value--
|
|
ElMessage.error(response.msg)
|
|
ElMessage.error(response.msg)
|
|
uploadRef.value?.handleRemove(uploadFile)
|
|
uploadRef.value?.handleRemove(uploadFile)
|
|
|
|
+ uploadedSuccessfully()
|
|
|
|
+ return
|
|
|
|
+ }
|
|
|
|
+ uploadList.value.push({ name: response.data.fileName, url: response.data.url, ossId: response.data.ossId })
|
|
|
|
+ uploadedSuccessfully()
|
|
|
|
+}
|
|
|
|
+
|
|
|
|
+// 上传结束处理
|
|
|
|
+const uploadedSuccessfully = () => {
|
|
|
|
+ debugger
|
|
|
|
+ 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
|
|
|
|
+ emit('update:modelValue', listToString(_fileList.value))
|
|
|
|
+ tryHideFullScreenLoading()
|
|
}
|
|
}
|
|
- // code: 200
|
|
|
|
- // fileName: "/profile/upload/2024/04/19/demo_20240419154324A003.txt"
|
|
|
|
- // msg: "操作成功"
|
|
|
|
- // newFileName: "demo_20240419154324A003.txt"
|
|
|
|
- // originalFilename: "demo.txt"
|
|
|
|
- // url: "http://localhost:8080/profile/upload/2024/04/19/demo_20240419154324A003.txt"
|
|
|
|
- // uploadList.push({ name: res.fileName, url: res.fileName });
|
|
|
|
|
|
+ // 监听表单验证
|
|
|
|
+ formItemContext?.prop && formContext?.validateField([formItemContext.prop as string])
|
|
}
|
|
}
|
|
|
|
|
|
/**
|
|
/**
|
|
@@ -180,178 +192,28 @@ const uploadSuccess = (response: any | undefined, uploadFile: UploadFile) => {
|
|
* @param file 删除的文件
|
|
* @param file 删除的文件
|
|
* */
|
|
* */
|
|
const handleRemove = (index: number) => {
|
|
const handleRemove = (index: number) => {
|
|
- // _fileList.value = _fileList.value.filter(item => item.url !== file.url || item.name !== file.name)
|
|
|
|
|
|
+ let ossId = _fileList.value[index].ossId
|
|
|
|
+ delOssApi(ossId)
|
|
_fileList.value.splice(index, 1)
|
|
_fileList.value.splice(index, 1)
|
|
- emit('update:modelValue', _fileList.value)
|
|
|
|
|
|
+ emit('update:modelValue', listToString(_fileList.value))
|
|
}
|
|
}
|
|
|
|
|
|
/**
|
|
/**
|
|
* @description 文件上传错误
|
|
* @description 文件上传错误
|
|
* */
|
|
* */
|
|
const uploadError = () => {
|
|
const uploadError = () => {
|
|
- ElNotification({
|
|
|
|
- title: '温馨提示',
|
|
|
|
- message: '文件上传失败,请您重新上传!',
|
|
|
|
- type: 'error'
|
|
|
|
- })
|
|
|
|
|
|
+ ElMessage.error('文件上传失败,请您重新上传!')
|
|
}
|
|
}
|
|
|
|
|
|
/**
|
|
/**
|
|
* @description 文件数超出
|
|
* @description 文件数超出
|
|
* */
|
|
* */
|
|
const handleExceed = () => {
|
|
const handleExceed = () => {
|
|
- ElNotification({
|
|
|
|
- title: '温馨提示',
|
|
|
|
- message: `当前最多只能上传 ${props.limit} 个文件 ,请移除后上传!`,
|
|
|
|
- type: 'warning'
|
|
|
|
- })
|
|
|
|
|
|
+ ElMessage.warning(`当前最多只能上传 ${props.limit} 个文件 ,请移除后上传!`)
|
|
}
|
|
}
|
|
-
|
|
|
|
-/**
|
|
|
|
- * @description 图片预览
|
|
|
|
- * @param file 预览的文件
|
|
|
|
- * */
|
|
|
|
-// const viewImageUrl = ref('')
|
|
|
|
-// const imgViewVisible = ref(false)
|
|
|
|
-// const handlePictureCardPreview: UploadProps['onPreview'] = file => {
|
|
|
|
-// viewImageUrl.value = file.url!
|
|
|
|
-// imgViewVisible.value = true
|
|
|
|
-// }
|
|
|
|
</script>
|
|
</script>
|
|
|
|
|
|
<style scoped lang="scss">
|
|
<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;
|
|
|
|
-// }
|
|
|
|
-// .is-error {
|
|
|
|
-// .upload {
|
|
|
|
-// :deep(.el-upload--picture-card),
|
|
|
|
-// :deep(.el-upload-dragger) {
|
|
|
|
-// border: 1px dashed var(--el-color-danger) !important;
|
|
|
|
-// &:hover {
|
|
|
|
-// border-color: var(--el-color-primary) !important;
|
|
|
|
-// }
|
|
|
|
-// }
|
|
|
|
-// }
|
|
|
|
-// }
|
|
|
|
-// :deep(.disabled) {
|
|
|
|
-// .el-upload--picture-card,
|
|
|
|
-// .el-upload-dragger {
|
|
|
|
-// cursor: not-allowed;
|
|
|
|
-// background: var(--el-disabled-bg-color) !important;
|
|
|
|
-// border: 1px dashed var(--el-border-color-darker);
|
|
|
|
-// &:hover {
|
|
|
|
-// border-color: var(--el-border-color-darker) !important;
|
|
|
|
-// }
|
|
|
|
-// }
|
|
|
|
-// }
|
|
|
|
-// .upload-box {
|
|
|
|
-// .no-border {
|
|
|
|
-// :deep(.el-upload--picture-card) {
|
|
|
|
-// border: none !important;
|
|
|
|
-// }
|
|
|
|
-// }
|
|
|
|
-// :deep(.upload) {
|
|
|
|
-// .el-upload-dragger {
|
|
|
|
-// display: flex;
|
|
|
|
-// align-items: center;
|
|
|
|
-// justify-content: center;
|
|
|
|
-// width: 100%;
|
|
|
|
-// height: 100%;
|
|
|
|
-// padding: 0;
|
|
|
|
-// overflow: hidden;
|
|
|
|
-// border: 1px dashed var(--el-border-color-darker);
|
|
|
|
-// border-radius: v-bind(borderRadius);
|
|
|
|
-// &:hover {
|
|
|
|
-// border: 1px dashed var(--el-color-primary);
|
|
|
|
-// }
|
|
|
|
-// }
|
|
|
|
-// .el-upload-dragger.is-dragover {
|
|
|
|
-// background-color: var(--el-color-primary-light-9);
|
|
|
|
-// border: 2px dashed var(--el-color-primary) !important;
|
|
|
|
-// }
|
|
|
|
-// .el-upload-list__item,
|
|
|
|
-// .el-upload--picture-card {
|
|
|
|
-// width: v-bind(width);
|
|
|
|
-// height: v-bind(height);
|
|
|
|
-// background-color: transparent;
|
|
|
|
-// border-radius: v-bind(borderRadius);
|
|
|
|
-// }
|
|
|
|
-// .upload-image {
|
|
|
|
-// width: 100%;
|
|
|
|
-// height: 100%;
|
|
|
|
-// object-fit: contain;
|
|
|
|
-// }
|
|
|
|
-// .upload-handle {
|
|
|
|
-// position: absolute;
|
|
|
|
-// top: 0;
|
|
|
|
-// right: 0;
|
|
|
|
-// box-sizing: border-box;
|
|
|
|
-// display: flex;
|
|
|
|
-// align-items: center;
|
|
|
|
-// justify-content: center;
|
|
|
|
-// width: 100%;
|
|
|
|
-// height: 100%;
|
|
|
|
-// cursor: pointer;
|
|
|
|
-// background: rgb(0 0 0 / 60%);
|
|
|
|
-// opacity: 0;
|
|
|
|
-// transition: var(--el-transition-duration-fast);
|
|
|
|
-// .handle-icon {
|
|
|
|
-// display: flex;
|
|
|
|
-// flex-direction: column;
|
|
|
|
-// align-items: center;
|
|
|
|
-// justify-content: center;
|
|
|
|
-// padding: 0 6%;
|
|
|
|
-// color: aliceblue;
|
|
|
|
-// .el-icon {
|
|
|
|
-// margin-bottom: 15%;
|
|
|
|
-// font-size: 140%;
|
|
|
|
-// }
|
|
|
|
-// span {
|
|
|
|
-// font-size: 100%;
|
|
|
|
-// }
|
|
|
|
-// }
|
|
|
|
-// }
|
|
|
|
-// .el-upload-list__item {
|
|
|
|
-// &:hover {
|
|
|
|
-// .upload-handle {
|
|
|
|
-// opacity: 1;
|
|
|
|
-// }
|
|
|
|
-// }
|
|
|
|
-// }
|
|
|
|
-// .upload-empty {
|
|
|
|
-// display: flex;
|
|
|
|
-// flex-direction: column;
|
|
|
|
-// align-items: center;
|
|
|
|
-// font-size: 12px;
|
|
|
|
-// line-height: 30px;
|
|
|
|
-// color: var(--el-color-info);
|
|
|
|
-// .el-icon {
|
|
|
|
-// font-size: 28px;
|
|
|
|
-// color: var(--el-text-color-secondary);
|
|
|
|
-// }
|
|
|
|
-// }
|
|
|
|
-// }
|
|
|
|
-// .el-upload__tip {
|
|
|
|
-// line-height: 15px;
|
|
|
|
-// text-align: center;
|
|
|
|
-// }
|
|
|
|
-// }
|
|
|
|
.upload-file-uploader {
|
|
.upload-file-uploader {
|
|
margin-bottom: 5px;
|
|
margin-bottom: 5px;
|
|
}
|
|
}
|