zy-vue-library/components/upload/index.vue

151 lines
4.6 KiB
Vue
Raw Normal View History

2025-10-22 11:19:51 +08:00
<template>
<el-upload
ref="uploadRef"
style="width: 100%"
:file-list="modelValue"
:action="action"
multiple
:limit="limit"
:list-type="listType"
:auto-upload="autoUpload"
:disabled="disabled"
:accept="accept"
:on-remove="onRemove"
:before-remove="beforeRemove"
:on-change="onChange"
:on-exceed="onExceed"
:on-preview="onPreview"
:http-request="httpRequest"
:show-file-list="showFileList"
:class="{ hide: modelValue.length === limit }"
>
<el-icon v-if="listType === 'picture-card'" size="32"><plus /></el-icon>
<el-button v-else type="primary">点击选择文件上传</el-button>
<template #tip>
<div class="mt-10 text-red">
<slot name="tip">
<div>{{ tip.join("") }}</div>
</slot>
</div>
</template>
</el-upload>
<el-dialog v-model="visible" title="查看图片">
<img :src="imageUrl" alt="Preview Image" style="width: 100%; object-fit: scale-down" />
</el-dialog>
</template>
<script setup>
import { computed, ref, useTemplateRef } from "vue";
import { ElMessage, ElMessageBox, ElUpload, ElIcon, ElButton, ElDialog } from "element-plus";
import { Plus } from "@element-plus/icons-vue";
import "element-plus/es/components/upload/style/css";
import "element-plus/es/components/icon/style/css";
import "element-plus/es/components/button/style/css";
import "element-plus/es/components/dialog/style/css";
defineOptions({
name: "AppUpload",
});
const props = defineProps({
autoUpload: { type: Boolean, default: false },
action: { type: String, default: "" },
limit: { type: Number, default: 1 },
listType: { type: String, default: "text" },
accept: { type: String, default: "" },
ratio: { type: String, default: "" },
disabled: { type: Boolean, default: false },
deleteToServer: { type: Boolean, default: false },
showFileList: { type: Boolean, default: true },
httpRequest: { type: Function },
size: { type: Number, default: 0 },
beforeRemove: { type: Function, default: () => {} },
});
const visible = ref(false);
const imageUrl = ref("");
const modelValue = defineModel({ type: Array, required: true });
const deleteFiles = defineModel("deleteFiles", {
type: Array,
default: () => [],
});
const emits = defineEmits(["preview", "delete"]);
const uploadRef = useTemplateRef("uploadRef");
const tip = computed(() =>
[
`最多上传${props.limit}个文件`,
props.accept
? `并且只能上传${props.accept
.replaceAll(".", "")
.split(",")
.join("、")}格式的文件`
: "可以上传任意格式的文件",
props.size ? `文件大小不能超过${props.size}M` : "",
props.ratio ? `只能上传${props.ratio}分辨率的图片` : "",
].filter(Boolean)
);
const onExceed = () => {
ElMessage.warning(`最多上传${props.limit}个文件`);
};
const beforeRemove = async (uploadFile) => {
if (props.deleteToServer && uploadFile.imgFilesId) {
await ElMessageBox.confirm("确定要删除吗?", {
type: "warning",
});
await props.beforeRemove(uploadFile);
}
};
const onRemove = (uploadFile, uploadFiles) => {
modelValue.value = uploadFiles;
deleteFiles.value.push(uploadFile);
emits("delete", uploadFile);
};
const onChange = (uploadFile, uploadFiles) => {
const accept = props.accept && props.accept.split(",");
const ratio = props.ratio && props.ratio.split("*");
const suffix = uploadFile.raw.name.substring(
uploadFile.raw.name.lastIndexOf("."),
uploadFile.raw.name.length
);
const size = props.size * 1024 * 1024;
if (ratio) {
const img = new Image();
img.src = uploadFile.url;
img.onload = () => {
if (img.width !== +ratio[0] && img.height !== +ratio[1]) {
ElMessage.warning(`只能上传${props.ratio}分辨率的图片`);
uploadRef.value.handleRemove(uploadFile.raw);
}
};
}
if (size) {
if (uploadFile.size > size) {
ElMessage.warning(`文件大小不能超过${props.size}M`);
uploadRef.value.handleRemove(uploadFile.raw);
}
}
if (accept) {
if (accept.includes(suffix)) {
modelValue.value = uploadFiles;
} else {
ElMessage.warning(`只能上传${props.accept}格式的文件`);
uploadRef.value.handleRemove(uploadFile.raw);
}
} else {
modelValue.value = uploadFiles;
}
};
const onPreview = (uploadFile) => {
if (props.listType === "picture-card") {
visible.value = true;
imageUrl.value = uploadFile.url;
} else {
emits("preview", uploadFile);
}
};
</script>
<style scoped lang="scss">
.hide :deep(.el-upload--picture-card) {
display: none;
}
</style>