151 lines
		
	
	
		
			4.6 KiB
		
	
	
	
		
			Vue
		
	
	
		
		
			
		
	
	
			151 lines
		
	
	
		
			4.6 KiB
		
	
	
	
		
			Vue
		
	
	
|  | <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> |