<template> <div> <el-upload v-if="listType === 'picture' || listType === 'text'" :name="name" :list-type="listType" :action="action" :multiple="multiple" :accept="accept" :file-list="FileList" v-bind="$attrs" v-on="$listeners" :before-upload="beforeUpload" :on-preview="handlePreview" :on-success="handleSuccess" :on-remove="handleRemove" > <slot> <el-button size="small" type="primary">点击上传</el-button> </slot> </el-upload> <el-upload v-else :name="name" :list-type="listType" :action="action" :multiple="multiple" :accept="accept" :file-list="FileList" v-bind="$attrs" v-on="$listeners" :before-upload="beforeUpload" :on-preview="handlePreview" :on-success="handleSuccess" :on-remove="handleRemove" > <slot> <i class="el-icon-plus"></i> </slot> </el-upload> <!-- 图片查看 --> <el-image-viewer v-if="preview" :appendToBody="false" :on-close=" () => { (preview = false), (filepaths = []); } " :url-list="filepaths" /> <!-- 视频预览 --> <div class="fixed left-0 top-0 z-[999] flex h-full w-full flex-col items-center justify-center gap-2 bg-[rgba(0,0,0,.5)]" v-if="show" > <video v-if="previewData.type === 'video'" class="h-[400px]" :src="previewData.url" autoplay muted controls ></video> <audio v-else-if="previewData.type === 'audio'" :src="previewData.url" autoplay muted controls ></audio> <i class="el-icon-circle-close cursor-pointer text-[40px] text-white" @click.self="show = false" ></i> </div> </div> </template> <script> export default { name: "YUpload", model: { prop: "value", event: "change", }, components: {}, props: { name: { type: String, default: "file", }, listType: { type: String, default: "text", }, multiple: { type: Boolean, default: false, }, value: { required: true, type: [String, Array], default: "", }, // 文件限制 accept: { type: String, default: "", }, // 上传数量 limit: { type: Number, validator: (value) => { return value >= 0; }, default: 1, // 0为不限制 }, // 上传文件大小限制mb 0为不限制 MB: { type: Number, validator: (value) => { return value >= 0; }, default: 10, }, action: { type: String, default: "/bill/file/commonupload", }, }, data() { return { FileList: [], imageType: ["png", "jpg", "jpeg", "gif", "svg"], videoType: ["mp4", "avi", "wmv", "rmvb", "flv", "mkv"], audioType: [ "mp3", "wav", "amr", "aac", "ogg", "wma", "flac", "ape", "mid", "wav", "wma", "mp3", "m4a", "m4r", "m4p", "m4b", "wma", "wav", "wma", "wma", ], // 图片预览 filepaths: [], preview: false, previewData: { type: "", url: "", }, show: false, }; }, watch: { value: { handler(newValue) { if (newValue) { if (Array.isArray(newValue)) { this.FileList = newValue.map((v) => { let index = v.lastIndexOf("/"); let name = v.slice(index + 1); return { name, url: v, }; }); } else { this.FileList = newValue.split(",").map((v) => { let index = v.lastIndexOf("/"); let name = v.slice(index + 1); return { name, url: v, }; }); } } else { this.FileList = []; } }, deep: true, immediate: true, }, }, computed: {}, created() {}, methods: { handleSuccess(response, file, fileList) { this.FileList = [...fileList]; if (file.status == "success") { if (file.response && file.response.code === -1) { let msg = file.response.msg || "上传失败"; this.$message.error(msg); fileList = fileList.filter((file) => file.response.code !== -1); } if (this.limit) { this.FileList = [...fileList].slice(-this.limit); } this.FileList = this.FileList.map((v) => { if (v.response) { v.url = v.response.url; } return v; }); let value; if (Array.isArray(this.value)) { value = this.FileList.map((v) => v.url); } else { value = this.FileList.map((v) => v.url).join(","); } this.$emit("change", value); this.$emit("success", { file, fileList }); } }, handleRemove(file, fileList) { let value; if (Array.isArray(this.value)) { value = fileList.map((v) => v.url); } else { value = fileList.map((v) => v.url).join(","); } this.$emit("change", value); this.$emit("success", { file, fileList }); }, beforeUpload(file) { let isType = true; let isExceed = true; return new Promise((resolve, reject) => { if (this.accept) { const fileType = this.accept.split(","); // 限制文件类型 let index = file.name.lastIndexOf("."); let type = file.name.slice(index); isType = fileType.includes(type); } if (!isType) { let msg = this.accept.replaceAll(",", "或者"); this.$message.error(`请上传${msg}文件!`); } if (this.MB) { isExceed = file.size / 1024 / 1024 <= this.MB; } if (!isExceed) { this.$message.error(`文件大小不能超过${this.MB}MB!`); } if (isType && isExceed) { resolve(file); } else { reject(); } }); }, // 预览 handlePreview(file) { let { url } = file; if (!url) return; let index = url.lastIndexOf("."); let type = url.slice(index + 1); if (this.imageType.includes(type)) { this.filepaths = [url]; this.preview = true; } else if (this.videoType.includes(type)) { this.previewData.type = "video"; this.previewData.url = url; this.show = true; } else if (this.audioType.includes(type)) { this.previewData.type = "audio"; this.previewData.url = url; this.show = true; } else { let a = document.createElement("a"); a.href = url; a.download = file.name; document.body.appendChild(a); a.click(); document.body.removeChild(a); } }, }, }; </script> <style lang="less" scoped></style>