From a1d7e81859f554f3a53680cc35f0f49bf1f77098 Mon Sep 17 00:00:00 2001
From: wwf <1971391498@qq.com>
Date: 星期四, 14 五月 2026 14:37:02 +0800
Subject: [PATCH] 导入项目
---
src/components/UploadFile/src/UploadImgs.vue | 329 ++++++++++++++++++++++++++++++++++++++++++++++++++++++
1 files changed, 329 insertions(+), 0 deletions(-)
diff --git a/src/components/UploadFile/src/UploadImgs.vue b/src/components/UploadFile/src/UploadImgs.vue
new file mode 100644
index 0000000..d1386e4
--- /dev/null
+++ b/src/components/UploadFile/src/UploadImgs.vue
@@ -0,0 +1,329 @@
+<template>
+ <div class="upload-box">
+ <el-upload
+ v-model:file-list="fileList"
+ :accept="fileType.join(',')"
+ :action="uploadUrl"
+ :before-upload="beforeUpload"
+ :class="['upload', drag ? 'no-border' : '']"
+ :disabled="disabled"
+ :drag="drag"
+ :http-request="httpRequest"
+ :limit="limit"
+ :multiple="true"
+ :on-error="uploadError"
+ :on-exceed="handleExceed"
+ :on-success="uploadSuccess"
+ list-type="picture-card"
+ >
+ <div class="upload-empty">
+ <slot name="empty">
+ <Icon icon="ep:plus" />
+ <!-- <span>璇蜂笂浼犲浘鐗�</span> -->
+ </slot>
+ </div>
+ <template #file="{ file }">
+ <img :src="file.url" class="upload-image" />
+ <div class="upload-handle" @click.stop>
+ <div class="handle-icon" @click="imagePreview(file.url!)">
+ <Icon icon="ep:zoom-in" />
+ <span>鏌ョ湅</span>
+ </div>
+ <div v-if="!disabled" class="handle-icon" @click="handleRemove(file)">
+ <Icon icon="ep:delete" />
+ <span>鍒犻櫎</span>
+ </div>
+ </div>
+ </template>
+ </el-upload>
+ <div class="el-upload__tip">
+ <slot name="tip"></slot>
+ </div>
+ </div>
+</template>
+<script lang="ts" setup>
+import type { UploadFile, UploadProps, UploadUserFile } from 'element-plus'
+import { ElNotification } from 'element-plus'
+import { createImageViewer } from '@/components/ImageViewer'
+
+import { propTypes } from '@/utils/propTypes'
+import { useUpload } from '@/components/UploadFile/src/useUpload'
+
+defineOptions({ name: 'UploadImgs' })
+
+const message = useMessage() // 娑堟伅寮圭獥
+// 鏌ョ湅鍥剧墖
+const imagePreview = (imgUrl: string) => {
+ createImageViewer({
+ zIndex: 9999999,
+ urlList: [imgUrl]
+ })
+}
+
+type FileTypes =
+ | 'image/apng'
+ | 'image/bmp'
+ | 'image/gif'
+ | 'image/jpeg'
+ | 'image/pjpeg'
+ | 'image/png'
+ | 'image/svg+xml'
+ | 'image/tiff'
+ | 'image/webp'
+ | 'image/x-icon'
+
+const props = defineProps({
+ modelValue: propTypes.oneOfType<string | string[]>([String, Array<String>]).isRequired,
+ drag: propTypes.bool.def(true), // 鏄惁鏀寔鎷栨嫿涓婁紶 ==> 闈炲繀浼狅紙榛樿涓� true锛�
+ disabled: propTypes.bool.def(false), // 鏄惁绂佺敤涓婁紶缁勪欢 ==> 闈炲繀浼狅紙榛樿涓� false锛�
+ limit: propTypes.number.def(5), // 鏈�澶у浘鐗囦笂浼犳暟 ==> 闈炲繀浼狅紙榛樿涓� 5寮狅級
+ fileSize: propTypes.number.def(5), // 鍥剧墖澶у皬闄愬埗 ==> 闈炲繀浼狅紙榛樿涓� 5M锛�
+ fileType: propTypes.array.def(['image/jpeg', 'image/png', 'image/gif']), // 鍥剧墖绫诲瀷闄愬埗 ==> 闈炲繀浼狅紙榛樿涓� ["image/jpeg", "image/png", "image/gif"]锛�
+ height: propTypes.string.def('150px'), // 缁勪欢楂樺害 ==> 闈炲繀浼狅紙榛樿涓� 150px锛�
+ width: propTypes.string.def('150px'), // 缁勪欢瀹藉害 ==> 闈炲繀浼狅紙榛樿涓� 150px锛�
+ borderradius: propTypes.string.def('8px'), // 缁勪欢杈规鍦嗚 ==> 闈炲繀浼狅紙榛樿涓� 8px锛�
+ directory: propTypes.string.def(undefined) // 涓婁紶鐩綍 ==> 闈炲繀浼狅紙榛樿涓� undefined锛�
+})
+
+const { uploadUrl, httpRequest } = useUpload(props.directory)
+
+const fileList = ref<UploadUserFile[]>([])
+const uploadNumber = ref<number>(0)
+const uploadList = ref<UploadUserFile[]>([])
+/**
+ * @description 鏂囦欢涓婁紶涔嬪墠鍒ゆ柇
+ * @param rawFile 涓婁紶鐨勬枃浠�
+ * */
+const beforeUpload: UploadProps['beforeUpload'] = (rawFile) => {
+ const imgSize = rawFile.size / 1024 / 1024 < props.fileSize
+ const imgType = props.fileType
+ const isValidType = imgType.includes(rawFile.type as FileTypes)
+ const isValidSize = imgSize
+
+ if (!isValidType)
+ ElNotification({
+ title: '娓╅Θ鎻愮ず',
+ message: '涓婁紶鍥剧墖涓嶇鍚堟墍闇�鐨勬牸寮忥紒',
+ type: 'warning'
+ })
+ if (!isValidSize)
+ ElNotification({
+ title: '娓╅Θ鎻愮ず',
+ message: `涓婁紶鍥剧墖澶у皬涓嶈兘瓒呰繃 ${props.fileSize}M锛乣,
+ type: 'warning'
+ })
+
+ // 鍙湁鍦ㄩ獙璇侀�氳繃鍚庢墠澧炲姞璁℃暟鍣�
+ if (isValidType && isValidSize) {
+ uploadNumber.value++
+ }
+
+ return isValidType && isValidSize
+}
+
+// 鍥剧墖涓婁紶鎴愬姛
+interface UploadEmits {
+ (e: 'update:modelValue', value: string[]): void
+}
+
+const emit = defineEmits<UploadEmits>()
+const uploadSuccess: UploadProps['onSuccess'] = (res: any): void => {
+ message.success('涓婁紶鎴愬姛')
+ // 鍒犻櫎鑷韩
+ const index = fileList.value.findIndex((item) => item.response?.data === res.data)
+ fileList.value.splice(index, 1)
+ uploadList.value.push({ name: res.data, url: res.data })
+ if (uploadList.value.length == uploadNumber.value) {
+ fileList.value.push(...uploadList.value)
+ uploadList.value = []
+ uploadNumber.value = 0
+ emitUpdateModelValue()
+ }
+}
+
+// 鐩戝惉妯″瀷缁戝畾鍊煎彉鍔�
+watch(
+ () => props.modelValue,
+ (val: string | string[]) => {
+ if (!val) {
+ fileList.value = [] // fix锛氬鐞嗘帀缂撳瓨锛岃〃鍗曢噸缃悗涓婁紶缁勪欢鐨勫唴瀹瑰苟娌℃湁閲嶇疆
+ return
+ }
+
+ fileList.value = [] // 淇濋殰鏁版嵁涓虹┖
+ fileList.value.push(
+ ...(val as string[]).map((url) => ({ name: url.substring(url.lastIndexOf('/') + 1), url }))
+ )
+ },
+ { immediate: true, deep: true }
+)
+// 鍙戦�佸浘鐗囬摼鎺ュ垪琛ㄦ洿鏂�
+const emitUpdateModelValue = () => {
+ let result: string[] = fileList.value.map((file) => file.url!)
+ emit('update:modelValue', result)
+}
+// 鍒犻櫎鍥剧墖
+const handleRemove = (uploadFile: UploadFile) => {
+ fileList.value = fileList.value.filter(
+ (item) => item.url !== uploadFile.url || item.name !== uploadFile.name
+ )
+ emit(
+ 'update:modelValue',
+ fileList.value.map((file) => file.url!)
+ )
+}
+
+// 鍥剧墖涓婁紶閿欒鎻愮ず
+const uploadError = () => {
+ ElNotification({
+ title: '娓╅Θ鎻愮ず',
+ message: '鍥剧墖涓婁紶澶辫触锛岃鎮ㄩ噸鏂颁笂浼狅紒',
+ type: 'error'
+ })
+ // 涓婁紶澶辫触鏃跺噺灏戣鏁板櫒锛岄伩鍏嶅悗缁笂浼犺闃诲
+ uploadNumber.value = Math.max(0, uploadNumber.value - 1)
+}
+
+// 鏂囦欢鏁拌秴鍑烘彁绀�
+const handleExceed = () => {
+ ElNotification({
+ title: '娓╅Θ鎻愮ず',
+ message: `褰撳墠鏈�澶氬彧鑳戒笂浼� ${props.limit} 寮犲浘鐗囷紝璇风Щ闄ゅ悗涓婁紶锛乣,
+ type: 'warning'
+ })
+}
+</script>
+
+<style lang="scss" scoped>
+.is-error {
+ .upload {
+ :deep(.el-upload--picture-card),
+ :deep(.el-upload-dragger) {
+ border: 1px dashed var(--el-color-danger) !important;
+
+ &:hover {
+ border-color: var(--el-color-primary) !important;
+ }
+ }
+ }
+}
+
+:deep(.disabled) {
+ .el-upload--picture-card,
+ .el-upload-dragger {
+ cursor: not-allowed;
+ background: var(--el-disabled-bg-color) !important;
+ border: 1px dashed var(--el-border-color-darker);
+
+ &:hover {
+ border-color: var(--el-border-color-darker) !important;
+ }
+ }
+}
+
+.upload-box {
+ .no-border {
+ :deep(.el-upload--picture-card) {
+ border: none !important;
+ }
+ }
+
+ :deep(.upload) {
+ .el-upload-dragger {
+ display: flex;
+ align-items: center;
+ justify-content: center;
+ width: 100%;
+ height: 100%;
+ padding: 0;
+ overflow: hidden;
+ border: 1px dashed var(--el-border-color-darker);
+ border-radius: v-bind(borderradius);
+
+ &:hover {
+ border: 1px dashed var(--el-color-primary);
+ }
+ }
+
+ .el-upload-dragger.is-dragover {
+ background-color: var(--el-color-primary-light-9);
+ border: 2px dashed var(--el-color-primary) !important;
+ }
+
+ .el-upload-list__item,
+ .el-upload--picture-card {
+ width: v-bind(width);
+ height: v-bind(height);
+ background-color: transparent;
+ border-radius: v-bind(borderradius);
+ }
+
+ .upload-image {
+ width: 100%;
+ height: 100%;
+ object-fit: contain;
+ }
+
+ .upload-handle {
+ position: absolute;
+ top: 0;
+ right: 0;
+ display: flex;
+ width: 100%;
+ height: 100%;
+ cursor: pointer;
+ background: rgb(0 0 0 / 60%);
+ opacity: 0;
+ box-sizing: border-box;
+ transition: var(--el-transition-duration-fast);
+ align-items: center;
+ justify-content: center;
+
+ .handle-icon {
+ display: flex;
+ flex-direction: column;
+ align-items: center;
+ justify-content: center;
+ padding: 0 6%;
+ color: aliceblue;
+
+ .el-icon {
+ margin-bottom: 15%;
+ font-size: 140%;
+ }
+
+ span {
+ font-size: 100%;
+ }
+ }
+ }
+
+ .el-upload-list__item {
+ &:hover {
+ .upload-handle {
+ opacity: 1;
+ }
+ }
+ }
+
+ .upload-empty {
+ display: flex;
+ flex-direction: column;
+ align-items: center;
+ font-size: 12px;
+ line-height: 30px;
+ color: var(--el-color-info);
+
+ .el-icon {
+ font-size: 28px;
+ color: var(--el-text-color-secondary);
+ }
+ }
+ }
+
+ .el-upload__tip {
+ line-height: 15px;
+ text-align: center;
+ }
+}
+</style>
--
Gitblit v1.8.0