Files
vue3-element-admin/src/components/Upload/ImageUpload.vue
2024-09-27 08:40:00 +08:00

255 lines
5.2 KiB
Vue
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
<!-- 图片上传组件 -->
<template>
<el-upload
v-model:file-list="fileList"
list-type="picture-card"
:class="
fileList.length >= props.limit || !props.showUploadBtn ? 'hide' : 'show'
"
:before-upload="handleBeforeUpload"
:action="props.action"
:headers="props.headers"
:data="props.data"
:name="props.name"
:on-success="handleSuccessFile"
:on-error="handleError"
:accept="props.accept"
:limit="props.limit"
>
<i-ep-plus />
<template #file="{ file }">
<div style="width: 100%">
<img class="el-upload-list__item-thumbnail" :src="file.url" alt="" />
<span class="el-upload-list__item-actions">
<span class="el-upload-list__item-preview" @click="previewImg(file)">
<el-icon><zoom-in /></el-icon>
</span>
<span
v-if="props.showDelBtn"
class="el-upload-list__item-delete"
@click="handleRemove(file)"
>
<el-icon><Delete /></el-icon>
</span>
</span>
</div>
</template>
</el-upload>
<el-image-viewer
v-if="viewVisible"
:zoom-rate="1.2"
@close="closePreview"
:initialIndex="initialIndex"
:url-list="viewFileList"
/>
</template>
<script setup lang="ts">
import {
UploadRawFile,
UploadUserFile,
UploadFile,
UploadProps,
} from "element-plus";
import FileAPI from "@/api/file";
import { getToken } from "@/utils/auth";
import { ResultEnum } from "@/enums/ResultEnum";
const emit = defineEmits(["update:modelValue"]);
const props = defineProps({
/**
* 文件路径集合
*/
modelValue: {
type: Array<string>,
default: () => [],
},
/**
* 上传地址
*/
action: {
type: String,
default: FileAPI.uploadUrl,
},
/**
* 请求头
*/
headers: {
type: Object,
default: () => {
return {
Authorization: getToken(),
};
},
},
/**
* 请求携带的额外参数
*/
data: {
type: Object,
default: () => {
return {};
},
},
/**
* 上传文件的参数名
*/
name: {
type: String,
default: "file",
},
/**
* 文件上传数量限制
*/
limit: {
type: Number,
default: 10,
},
/**
* 是否显示删除按钮
*/
showDelBtn: {
type: Boolean,
default: true,
},
/**
* 是否显示上传按钮
*/
showUploadBtn: {
type: Boolean,
default: true,
},
/**
* 单张图片最大大小
*/
uploadMaxSize: {
type: Number,
default: 2 * 1024 * 1024,
},
/**
* 上传文件类型
*/
accept: {
type: String,
default: "image/*",
},
});
const viewVisible = ref(false);
const initialIndex = ref(0);
const fileList = ref([] as UploadUserFile[]);
const valFileList = ref([] as string[]);
const viewFileList = ref([] as string[]);
watch(
() => props.modelValue,
(newVal: string[]) => {
const filePaths = fileList.value.map((file) => file.url);
// 监听modelValue文件集合值未变化时跳过赋值
if (
filePaths.length > 0 &&
filePaths.length === newVal.length &&
filePaths.every((x) => newVal.some((y) => y === x)) &&
newVal.every((y) => filePaths.some((x) => x === y))
) {
return;
}
if (newVal.length <= 0) {
fileList.value = [];
viewFileList.value = [];
valFileList.value = [];
return;
}
fileList.value = newVal.map((filePath) => {
return { url: filePath } as UploadUserFile;
});
valFileList.value = newVal.map((filePath) => {
return filePath;
});
},
{ immediate: true }
);
/**
* 上传成功回调
*
* @param options
*/
const handleSuccessFile = (response: any, file: UploadFile) => {
if (response.code === ResultEnum.SUCCESS) {
ElMessage.success("上传成功");
valFileList.value.push(response.data.url);
emit("update:modelValue", valFileList.value);
return;
} else {
ElMessage.error(response.msg || "上传失败");
}
};
const handleError = (error: any) => {
ElMessage.error("上传失败");
};
/**
* 删除图片
*/
function handleRemove(removeFile: UploadFile) {
const filePath = removeFile.url;
if (filePath) {
FileAPI.deleteByPath(filePath).then(() => {
valFileList.value = valFileList.value.filter((x) => x !== filePath);
// 删除成功回调
emit("update:modelValue", valFileList.value);
});
}
}
/**
* 限制用户上传文件的格式和大小
*/
function handleBeforeUpload(file: UploadRawFile) {
if (file.size > props.uploadMaxSize) {
ElMessage.warning(
"上传图片不能大于" + Math.trunc(props.uploadMaxSize / 1024 / 1024) + "M"
);
return false;
}
return true;
}
/**
* 预览图片
*/
const previewImg: UploadProps["onPreview"] = (uploadFile: UploadFile) => {
viewFileList.value = fileList.value.map((file) => file.url!);
initialIndex.value = fileList.value.findIndex(
(file) => file.url === uploadFile.url
);
viewVisible.value = true;
};
/**
* 关闭预览
*/
const closePreview = () => {
viewVisible.value = false;
};
</script>
<style lang="scss" scoped>
.hide {
:deep(.el-upload--picture-card) {
display: none;
}
}
.show {
:deep(.el-upload--picture-card) {
display: flex;
}
}
</style>