|
|
@@ -2,22 +2,28 @@
|
|
|
import { useUserStore } from '@/stores/user'
|
|
|
import { ACCESS_TOKEN } from '@/utils/constants'
|
|
|
import { ElMessage } from 'element-plus'
|
|
|
-import type { UploadProps } from 'element-plus'
|
|
|
-import { isAbsolutePath } from '@/utils/utils'
|
|
|
+import { isAbsolutePath, ossUpload } from '@/utils/utils'
|
|
|
import config from '@/config/defaultSetting'
|
|
|
+import type { UploadProps, UploadFile } from 'element-plus'
|
|
|
+import type { BasicFormItem } from '@/types/form'
|
|
|
|
|
|
interface Props {
|
|
|
+ item: BasicFormItem
|
|
|
modelValue: any
|
|
|
size?: number | string
|
|
|
iconSize?: number | string
|
|
|
fileSize?: number | string
|
|
|
uploadApi?: string
|
|
|
+ oss?: boolean
|
|
|
+ limit?: number
|
|
|
}
|
|
|
const props = withDefaults(defineProps<Props>(), {
|
|
|
size: '148px',
|
|
|
iconSize: '28px',
|
|
|
uploadApi: config.uploadApi,
|
|
|
- fileSize: 10
|
|
|
+ fileSize: 10,
|
|
|
+ oss: config.oss,
|
|
|
+ limit: 1
|
|
|
})
|
|
|
const emits = defineEmits(['update:modelValue'])
|
|
|
|
|
|
@@ -32,8 +38,12 @@ const headers = reactive({
|
|
|
[ACCESS_TOKEN]: user.token
|
|
|
})
|
|
|
|
|
|
+const limit = Number(props.limit) || 1
|
|
|
+
|
|
|
+const uploadRef = ref()
|
|
|
+// 在上传之前对文件进行验证
|
|
|
const fileSize = Number(props.fileSize) || 10
|
|
|
-const beforeAvatarUpload: UploadProps['beforeUpload'] = rawFile => {
|
|
|
+const beforeUpload: UploadProps['beforeUpload'] = rawFile => {
|
|
|
if (rawFile.size / 1024 / 1024 > fileSize) {
|
|
|
ElMessage.error(`图片大小不能超过${fileSize}MB!`)
|
|
|
return false
|
|
|
@@ -41,28 +51,73 @@ const beforeAvatarUpload: UploadProps['beforeUpload'] = rawFile => {
|
|
|
return true
|
|
|
}
|
|
|
|
|
|
-// 图片上传
|
|
|
-const handleUploadSuccess: UploadProps['onSuccess'] = response => {
|
|
|
+// 图片上传成功
|
|
|
+const handleUploadSuccess: UploadProps['onSuccess'] = (response, uploadFile: UploadFile) => {
|
|
|
if (response.success || response.code === 200) {
|
|
|
- modelValue.value = config.uploadSuccessCb(response)
|
|
|
+ // 附加oss路径
|
|
|
+ modelValue.value.forEach((item: any) => {
|
|
|
+ if (item.uid === uploadFile.uid) {
|
|
|
+ item.extra = props.oss ? response.url : config.uploadSuccessCb(response)
|
|
|
+ }
|
|
|
+ })
|
|
|
} else {
|
|
|
ElMessage.error(response.msg)
|
|
|
}
|
|
|
}
|
|
|
+// 删除图片
|
|
|
+const handleRemove = (file: UploadFile) => {
|
|
|
+ uploadRef.value.handleRemove(file)
|
|
|
+}
|
|
|
+// 图片预览
|
|
|
+const showViewer = ref(false)
|
|
|
+const previewIndex = ref(0)
|
|
|
+const previewList = computed(() => modelValue.value.map((item: any) => item.url))
|
|
|
+const handlePreview = (file: UploadFile) => {
|
|
|
+ previewIndex.value = modelValue.value.findIndex((item: any) => item.url === file.url)
|
|
|
+ showViewer.value = true
|
|
|
+}
|
|
|
+const closeViewer = () => {
|
|
|
+ showViewer.value = false
|
|
|
+}
|
|
|
+
|
|
|
+// 接口需要的属性
|
|
|
+props.item.extra = computed(() => modelValue.value.map((item: any) => item.extra))
|
|
|
+
|
|
|
+//
|
|
|
+const attrs: any = props.oss ? { 'http-request': ossUpload } : {}
|
|
|
+if (!props.item.props?.onSuccess) {
|
|
|
+ attrs['on-success'] = handleUploadSuccess
|
|
|
+}
|
|
|
</script>
|
|
|
|
|
|
<template>
|
|
|
<el-upload
|
|
|
- :on-success="handleUploadSuccess"
|
|
|
- :before-upload="beforeAvatarUpload"
|
|
|
+ ref="uploadRef"
|
|
|
+ v-model:file-list="modelValue"
|
|
|
+ :class="{ 'is-disabled': modelValue.length >= limit }"
|
|
|
:action="isAbsolutePath(props.uploadApi) ? props.uploadApi : baseApi + props.uploadApi"
|
|
|
:headers="headers"
|
|
|
- :show-file-list="false"
|
|
|
+ :before-upload="beforeUpload"
|
|
|
+ :limit="limit"
|
|
|
+ list-type="picture-card"
|
|
|
accept="image/*"
|
|
|
+ v-bind="{ ...attrs, ...$attrs }"
|
|
|
>
|
|
|
- <img v-if="modelValue" :src="modelValue" class="avatar" />
|
|
|
- <el-icon v-else class="avatar-uploader-icon" :style="{ fontSize: iconSize }"><Plus /></el-icon>
|
|
|
+ <el-icon class="avatar-uploader-icon" :style="{ fontSize: iconSize }"><Plus /></el-icon>
|
|
|
+ <template #file="{ file }">
|
|
|
+ <el-image class="el-upload-list__item-thumbnail" :src="file.url" fit="cover" />
|
|
|
+ <span class="el-upload-list__item-actions">
|
|
|
+ <span class="el-upload-list__item-preview" @click="handlePreview(file)">
|
|
|
+ <el-icon><zoom-in /></el-icon>
|
|
|
+ </span>
|
|
|
+
|
|
|
+ <span class="el-upload-list__item-delete" @click="handleRemove(file)">
|
|
|
+ <el-icon><Delete /></el-icon>
|
|
|
+ </span>
|
|
|
+ </span>
|
|
|
+ </template>
|
|
|
</el-upload>
|
|
|
+ <el-image-viewer v-if="showViewer" :url-list="previewList" :initial-index="previewIndex" @close="closeViewer" />
|
|
|
</template>
|
|
|
|
|
|
<style lang="scss" scoped>
|
|
|
@@ -79,14 +134,12 @@ const handleUploadSuccess: UploadProps['onSuccess'] = response => {
|
|
|
&:hover {
|
|
|
border-color: var(--el-color-primary);
|
|
|
}
|
|
|
-
|
|
|
- img {
|
|
|
- width: 100%;
|
|
|
- height: 100%;
|
|
|
- object-fit: contain;
|
|
|
- }
|
|
|
}
|
|
|
-.el-icon.avatar-uploader-icon {
|
|
|
- color: #8c939d;
|
|
|
+:deep(.el-upload-list--picture-card .el-upload-list__item) {
|
|
|
+ width: v-bind(size);
|
|
|
+ height: v-bind(size);
|
|
|
+}
|
|
|
+.is-disabled :deep(.el-upload--picture-card) {
|
|
|
+ display: none;
|
|
|
}
|
|
|
</style>
|