|
@@ -1,18 +1,28 @@
|
|
|
<script setup lang="ts">
|
|
|
import { ElMessage } from 'element-plus'
|
|
|
-import { imageUploadProps, imageUploadEmits } from './props'
|
|
|
+import type { ImageUploadProps } from './props'
|
|
|
+import { imageUploadEmits } from './props'
|
|
|
import type { UploadItem } from './types'
|
|
|
+import { uuid } from '@/utils/utils'
|
|
|
+import axios, { type AxiosProgressEvent } from 'axios'
|
|
|
|
|
|
-const emit = defineEmits(imageUploadEmits)
|
|
|
+const emits = defineEmits(imageUploadEmits)
|
|
|
|
|
|
-const props = defineProps(imageUploadProps)
|
|
|
+const props = withDefaults(defineProps<ImageUploadProps>(), {
|
|
|
+ fileName: 'file',
|
|
|
+ autoUpload: true,
|
|
|
+ preview: true,
|
|
|
+ limit: 9,
|
|
|
+ fileSize: 5,
|
|
|
+ iconSize: 28
|
|
|
+})
|
|
|
|
|
|
const images = ref<UploadItem[]>([])
|
|
|
|
|
|
// 是否可上传
|
|
|
const isUpload = computed<boolean>(() => {
|
|
|
return (
|
|
|
- !props.readonly &&
|
|
|
+ !props.disabled &&
|
|
|
!(typeof props.limit === 'number' && props.limit > 0 && images.value != null && images.value.length >= props.limit)
|
|
|
)
|
|
|
})
|
|
@@ -32,7 +42,6 @@ const previewList = computed(() => {
|
|
|
|
|
|
/* 选择文件 */
|
|
|
const onUpload = (file: File) => {
|
|
|
- console.log(file)
|
|
|
if (!isUpload.value || props.disabled) {
|
|
|
return false
|
|
|
}
|
|
@@ -46,7 +55,7 @@ const onUpload = (file: File) => {
|
|
|
}
|
|
|
|
|
|
const item: UploadItem = {
|
|
|
- key: Date.now(),
|
|
|
+ key: uuid(),
|
|
|
name: file.name,
|
|
|
status: void 0,
|
|
|
progress: 0,
|
|
@@ -57,17 +66,41 @@ const onUpload = (file: File) => {
|
|
|
images.value.push(item)
|
|
|
// 是否自动上传
|
|
|
if (props.autoUpload) {
|
|
|
- uploadItem(item)
|
|
|
+ // 自动上传最后一个文件
|
|
|
+ uploadItem(images.value.at(-1) as UploadItem)
|
|
|
}
|
|
|
return false
|
|
|
}
|
|
|
|
|
|
/* 上传文件 */
|
|
|
const uploadItem = (item: UploadItem) => {
|
|
|
- if (typeof props.uploadFunction === 'function') {
|
|
|
- props.uploadFunction(item)
|
|
|
+ if (!props.action && typeof props.uploadFunction === 'function') {
|
|
|
+ console.log('请传入action路径或者uploadFunction上传方法')
|
|
|
+ return false
|
|
|
+ }
|
|
|
+ // 如果配置了上传路径
|
|
|
+ if (props.action) {
|
|
|
+ const formData = new FormData()
|
|
|
+ formData.append(props.fileName, item.file as File)
|
|
|
+ axios
|
|
|
+ .post(props.action, formData, {
|
|
|
+ onUploadProgress: (e: AxiosProgressEvent) => {
|
|
|
+ if (e.total != null) {
|
|
|
+ item.progress = (e.loaded / e.total) * 100
|
|
|
+ }
|
|
|
+ }
|
|
|
+ })
|
|
|
+ .then(res => {
|
|
|
+ item.status = 'success'
|
|
|
+ item.url = res.data
|
|
|
+ })
|
|
|
+ .catch(() => {
|
|
|
+ item.status = 'danger'
|
|
|
+ })
|
|
|
} else {
|
|
|
- console.log('请传入uploadFunction')
|
|
|
+ // 自定义方法上传
|
|
|
+ if (typeof props.uploadFunction != 'function') return false
|
|
|
+ ;(props.uploadFunction as Function)(item)
|
|
|
}
|
|
|
}
|
|
|
|
|
@@ -82,7 +115,7 @@ const submit = () => {
|
|
|
|
|
|
/* 删除图片 */
|
|
|
const onRemove = (index: number) => {
|
|
|
- emit('remove', images.value[index])
|
|
|
+ emits('remove', images.value[index])
|
|
|
images.value.splice(index, 1)
|
|
|
}
|
|
|
|
|
@@ -92,22 +125,32 @@ const onRetry = (index: number) => {
|
|
|
}
|
|
|
|
|
|
/* 修改modelValue */
|
|
|
-const updateModelValue = (items: UploadItem[]) => {
|
|
|
- // ToDo:这里需要优化,最后格式为'url1,url2,url3'
|
|
|
- emit('update:modelValue', items)
|
|
|
+const updateModelValue = (items: any) => {
|
|
|
+ emits('update:modelValue', items.map((x: UploadItem) => x.url).join(',') || '')
|
|
|
}
|
|
|
|
|
|
watch(
|
|
|
() => props.modelValue,
|
|
|
() => {
|
|
|
- // ToDo:这里需要优化,需要自行处理格式
|
|
|
- images.value = props.modelValue || []
|
|
|
+ if (typeof props.modelValue === 'string' && props.modelValue.startsWith('http')) {
|
|
|
+ // 传进来的数据转换成内部需要数据
|
|
|
+ const formatData = typeof props.modelValue === 'string' ? props.modelValue.split(',').filter(x => x) : []
|
|
|
+ const datas: UploadItem[] = formatData.map((x: string) => {
|
|
|
+ return {
|
|
|
+ key: uuid(),
|
|
|
+ url: x,
|
|
|
+ status: 'success',
|
|
|
+ name: x.split('/').pop()
|
|
|
+ }
|
|
|
+ })
|
|
|
+ images.value = datas
|
|
|
+ }
|
|
|
},
|
|
|
{ immediate: true }
|
|
|
)
|
|
|
|
|
|
watch(
|
|
|
- images.value,
|
|
|
+ images,
|
|
|
() => {
|
|
|
updateModelValue(images.value)
|
|
|
},
|
|
@@ -124,9 +167,9 @@ defineExpose({
|
|
|
|
|
|
<template>
|
|
|
<div class="upload-container">
|
|
|
- <div class="upload-image" v-for="(item, index) in modelValue" :key="item.key">
|
|
|
+ <div class="upload-image" v-for="(item, index) in images" :key="item.key">
|
|
|
<el-image :src="item.url" :preview-src-list="previewList" :initial-index="index" fit="cover"></el-image>
|
|
|
- <div v-if="!readonly && !disabled" class="upload-remove" @click.stop="onRemove(index)">
|
|
|
+ <div v-if="!disabled" class="upload-remove" @click.stop="onRemove(index)">
|
|
|
<el-icon size="14">
|
|
|
<Close />
|
|
|
</el-icon>
|
|
@@ -155,7 +198,7 @@ defineExpose({
|
|
|
<div>
|
|
|
<el-upload
|
|
|
action=""
|
|
|
- :accept="accept"
|
|
|
+ accept="image/*"
|
|
|
:multiple="multiple"
|
|
|
:disabled="disabled"
|
|
|
:show-file-list="false"
|
|
@@ -163,8 +206,8 @@ defineExpose({
|
|
|
:drag="drag"
|
|
|
v-if="isUpload"
|
|
|
>
|
|
|
- <div class="upload-plus" :style="buttonStyle">
|
|
|
- <el-icon size="30">
|
|
|
+ <div class="upload-plus">
|
|
|
+ <el-icon :size="iconSize">
|
|
|
<Plus />
|
|
|
</el-icon>
|
|
|
</div>
|
|
@@ -230,6 +273,10 @@ defineExpose({
|
|
|
margin-top: 5px;
|
|
|
}
|
|
|
}
|
|
|
+ .el-image {
|
|
|
+ width: 100%;
|
|
|
+ height: 100%;
|
|
|
+ }
|
|
|
}
|
|
|
.upload-plus {
|
|
|
width: 100px;
|
|
@@ -240,7 +287,7 @@ defineExpose({
|
|
|
color: var(--el-color-info);
|
|
|
border: 1px dashed #dcdfe6;
|
|
|
border-radius: var(--el-border-radius-base);
|
|
|
- &:hover {
|
|
|
+ &:not(.disabled):hover {
|
|
|
border-color: var(--el-color-primary);
|
|
|
}
|
|
|
}
|