From 2d31f354cb9db536c7c5e0a4143031a8070d8d42 Mon Sep 17 00:00:00 2001 From: "Ray.Hao" <1490493387@qq.com> Date: Sun, 2 Feb 2025 22:05:42 +0800 Subject: [PATCH] =?UTF-8?q?refactor:=20:recycle:=20=E6=96=87=E4=BB=B6?= =?UTF-8?q?=E5=92=8C=E5=9B=BE=E7=89=87=E4=B8=8A=E4=BC=A0=E7=BB=84=E4=BB=B6?= =?UTF-8?q?=E9=87=8D=E6=9E=84=EF=BC=8C=E7=B2=BE=E7=AE=80=E5=8F=82=E6=95=B0?= =?UTF-8?q?=E5=92=8C=E9=99=8D=E4=BD=8E=E4=BB=A3=E7=A0=81=E5=A4=8D=E6=9D=82?= =?UTF-8?q?=E5=BA=A6?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/api/file/index.ts | 15 +- src/components/Upload/FileUpload.vue | 321 +++++++----------- src/components/Upload/ImageUpload.vue | 344 -------------------- src/components/Upload/MultiImageUpload.vue | 125 +++---- src/components/Upload/SingleImageUpload.vue | 202 ++++++++++++ src/types/components.d.ts | 2 +- src/views/demo/upload.vue | 16 +- 7 files changed, 382 insertions(+), 643 deletions(-) delete mode 100644 src/components/Upload/ImageUpload.vue create mode 100644 src/components/Upload/SingleImageUpload.vue diff --git a/src/api/file/index.ts b/src/api/file/index.ts index 509e6955..c2076a19 100644 --- a/src/api/file/index.ts +++ b/src/api/file/index.ts @@ -1,19 +1,12 @@ import request from "@/utils/request"; const FileAPI = { - /** - * 文件上传地址 - */ - uploadUrl: import.meta.env.VITE_APP_BASE_API + "/api/v1/files", - /** * 上传文件 * - * @param file + * @param formData */ - upload(file: File) { - const formData = new FormData(); - formData.append("file", file); + upload(formData: FormData) { return request({ url: "/api/v1/files", method: "post", @@ -29,7 +22,7 @@ const FileAPI = { * * @param filePath 文件完整路径 */ - deleteByPath(filePath?: string) { + delete(filePath?: string) { return request({ url: "/api/v1/files", method: "delete", @@ -42,7 +35,7 @@ const FileAPI = { * @param url * @param fileName */ - downloadFile(url: string, fileName?: string) { + download(url: string, fileName?: string) { return request({ url: url, method: "get", diff --git a/src/components/Upload/FileUpload.vue b/src/components/Upload/FileUpload.vue index fed6f0b8..15cacd61 100644 --- a/src/components/Upload/FileUpload.vue +++ b/src/components/Upload/FileUpload.vue @@ -3,53 +3,41 @@
- + + {{ props.uploadBtnText }} - + + +
@@ -57,98 +45,13 @@ import { UploadRawFile, UploadUserFile, - UploadFile, UploadProgressEvent, - UploadFiles, + UploadRequestOptions, } from "element-plus"; -import FileAPI from "@/api/file"; -import { getToken } from "@/utils/auth"; -import { ResultEnum } from "@/enums/ResultEnum"; +import FileAPI, { FileInfo } from "@/api/file"; -const emit = defineEmits(["update:modelValue"]); const props = defineProps({ - /** - * 文件集合 - */ - modelValue: { - type: Array, - default: () => [], - }, - /** - * 上传地址 - */ - action: { - type: String, - default: FileAPI.uploadUrl, - }, - /** - * 文件上传数量限制 - */ - limit: { - type: Number, - default: 10, - }, - /** - * 是否显示删除按钮 - */ - showDelBtn: { - type: Boolean, - default: true, - }, - /** - * 是否显示上传按钮 - */ - showUploadBtn: { - type: Boolean, - default: true, - }, - /** - * 单个文件上传大小限制(单位MB) - */ - maxSize: { - type: Number, - default: 10, - }, - /** - * 上传文件类型 - */ - accept: { - type: String, - default: "*", - }, - /** - * 上传按钮文本 - */ - uploadBtnText: { - type: String, - default: "上传文件", - }, - /** - * 是否展示提示信息 - */ - showTip: { - type: Boolean, - default: false, - }, - /** - * 提示信息内容 - */ - tip: { - type: String, - default: "", - }, - /** - * 请求头 - */ - headers: { - type: Object, - default: () => { - return { - Authorization: getToken(), - }; - }, - }, /** * 请求携带的额外参数 */ @@ -165,6 +68,35 @@ const props = defineProps({ type: String, default: "file", }, + /** + * 文件上传数量限制 + */ + limit: { + type: Number, + default: 10, + }, + /** + * 单个文件上传大小限制(单位MB) + */ + maxFileSize: { + type: Number, + default: 10, + }, + /** + * 上传文件类型 + */ + accept: { + type: String, + default: "*", + }, + /** + * 上传按钮文本 + */ + uploadBtnText: { + type: String, + default: "上传文件", + }, + /** * 样式 */ @@ -178,119 +110,108 @@ const props = defineProps({ }, }); +const modelValue = defineModel("modelValue", { + type: [Array] as PropType, + required: true, + default: () => [], +}); + const fileList = ref([] as UploadUserFile[]); -const valFileList = ref([] as UploadUserFile[]); -const showUploadPercent = ref(false); -const uploadPercent = ref(0); +const showProgress = ref(false); +const progressPercent = ref(0); + +// 监听 modelValue 转换用于显示的 fileList watch( - () => props.modelValue, - (newVal: UploadUserFile[]) => { - const filePaths = fileList.value.map((file) => file.url); - const fileNames = fileList.value.map((file) => file.name); - // 监听modelValue文件集合值未变化时,跳过赋值 - if ( - filePaths.length > 0 && - filePaths.length === newVal.length && - filePaths.every((x) => newVal.some((y) => y.url === x)) && - newVal.every((y) => filePaths.some((x) => x === y.url)) && - fileNames.every((x) => newVal.some((y) => y.name === x)) && - newVal.every((y) => fileNames.some((x) => x === y.name)) - ) { - return; - } - - if (newVal.length <= 0) { - fileList.value = []; - valFileList.value = []; - return; - } - - fileList.value = newVal.map((file) => { - return { name: file.name, url: file.url } as UploadFile; - }); - - valFileList.value = newVal.map((file) => { - return { name: file.name, url: file.url } as UploadFile; + modelValue, + (value) => { + fileList.value = value.map((url) => { + const name = url.substring(url.lastIndexOf("/") + 1); + return { + name: name, + url: url, + } as UploadUserFile; }); }, - { immediate: true } + { + immediate: true, + } ); /** - * 限制用户上传文件的大小 + * 上传前校验 */ function handleBeforeUpload(file: UploadRawFile) { - if (file.size > props.maxSize * 1024 * 1024) { - ElMessage.warning("上传文件不能大于" + props.maxSize + "Mb"); + // 限制文件大小 + if (file.size > props.maxFileSize * 1024 * 1024) { + ElMessage.warning("上传图片不能大于" + props.maxFileSize + "M"); return false; } - uploadPercent.value = 0; - showUploadPercent.value = true; return true; } -/** - * 上传成功回调方法 - * @param response 响应题 - * @param file 上传文件 + +/* + * 上传文件 */ -const handleSuccessFile = (response: any, file: UploadFile) => { - showUploadPercent.value = false; - uploadPercent.value = 0; - if (response.code === ResultEnum.SUCCESS) { - ElMessage.success("上传成功"); - valFileList.value.push({ - name: file.name, - url: response.data.url, +function handleUpload(options: UploadRequestOptions) { + return new Promise((resolve, reject) => { + const file = options.file; + + const formData = new FormData(); + formData.append(props.name, file); + + // 处理附加参数 + Object.keys(props.data).forEach((key) => { + formData.append(key, props.data[key]); }); - emit("update:modelValue", valFileList.value); - return; - } else { - ElMessage.error(response.msg || "上传失败"); - } + + FileAPI.upload(formData) + .then((data) => { + resolve(data); + }) + .catch((error) => { + reject(error); + }); + }); +} + +/** + * 上传进度 + * + * @param event + */ +const handleProgress = (event: UploadProgressEvent) => { + progressPercent.value = event.percent; +}; + +/** + * 上传成功 + */ +const handleSuccess = (fileInfo: FileInfo) => { + ElMessage.success("上传成功"); + modelValue.value = [...modelValue.value, fileInfo.url]; }; const handleError = (error: any) => { - showUploadPercent.value = false; - uploadPercent.value = 0; ElMessage.error("上传失败"); }; -const customColorMethod = (percentage: number) => { - if (percentage < 30) { - return "#909399"; - } - if (percentage < 70) { - return "#375ee8"; - } - return "#67c23a"; -}; - -const handleProgress = (event: UploadProgressEvent) => { - uploadPercent.value = event.percent; -}; - /** * 删除文件 */ -function handleRemove(removeFile: UploadUserFile) { - const filePath = removeFile.url; - if (filePath) { - FileAPI.deleteByPath(filePath).then(() => { - // 删除成功回调 - valFileList.value = valFileList.value.filter((file) => file.url !== filePath); - emit("update:modelValue", valFileList.value); - }); - } +function handleRemove(fileUrl: string) { + FileAPI.delete(fileUrl).then(() => { + modelValue.value = modelValue.value.filter((url) => url !== fileUrl); + }); } /** * 下载文件 */ -function downloadFile(file: UploadUserFile) { - const filePath = file.url; - if (filePath) { - FileAPI.downloadFile(filePath, file.name); +function handleDownload(file: UploadUserFile) { + const { url, name } = file; + if (url) { + FileAPI.download(url, name); } } @@ -313,16 +234,4 @@ function downloadFile(file: UploadUserFile) { :deep(.el-upload-list__item) { margin: 0; } - -.show-upload-btn { - :deep(.el-upload) { - display: inline-flex; - } -} - -.hide-upload-btn { - :deep(.el-upload) { - display: none; - } -} diff --git a/src/components/Upload/ImageUpload.vue b/src/components/Upload/ImageUpload.vue deleted file mode 100644 index 0bbe42ea..00000000 --- a/src/components/Upload/ImageUpload.vue +++ /dev/null @@ -1,344 +0,0 @@ - - - - diff --git a/src/components/Upload/MultiImageUpload.vue b/src/components/Upload/MultiImageUpload.vue index 1c11a033..4a790079 100644 --- a/src/components/Upload/MultiImageUpload.vue +++ b/src/components/Upload/MultiImageUpload.vue @@ -1,57 +1,52 @@ - + diff --git a/src/components/Upload/SingleImageUpload.vue b/src/components/Upload/SingleImageUpload.vue new file mode 100644 index 00000000..817d5788 --- /dev/null +++ b/src/components/Upload/SingleImageUpload.vue @@ -0,0 +1,202 @@ + + + + + + diff --git a/src/types/components.d.ts b/src/types/components.d.ts index fcc072db..d03a6b64 100644 --- a/src/types/components.d.ts +++ b/src/types/components.d.ts @@ -84,12 +84,12 @@ declare module "vue" { SidebarMenuItem: (typeof import("./../layout/components/Sidebar/components/SidebarMenuItem.vue"))["default"]; SidebarMenuItemTitle: (typeof import("./../layout/components/Sidebar/components/SidebarMenuItemTitle.vue"))["default"]; SidebarMixTopMenu: (typeof import("./../layout/components/Sidebar/components/SidebarMixTopMenu.vue"))["default"]; + SingleImageUpload: (typeof import("./../components/Upload/SingleImageUpload.vue"))["default"]; SizeSelect: (typeof import("./../components/SizeSelect/index.vue"))["default"]; SvgIcon: (typeof import("./../components/SvgIcon/index.vue"))["default"]; TableSelect: (typeof import("./../components/TableSelect/index.vue"))["default"]; TagsView: (typeof import("./../layout/components/TagsView/index.vue"))["default"]; ThemeColorPicker: (typeof import("./../layout/components/Settings/components/ThemeColorPicker.vue"))["default"]; - SingleImageUpload: (typeof import("./../components/Upload/SingleImageUpload.vue"))["default"]; WangEditor: (typeof import("./../components/WangEditor/index.vue"))["default"]; } export interface ComponentCustomProperties { diff --git a/src/views/demo/upload.vue b/src/views/demo/upload.vue index 901a3edd..b97b71f9 100644 --- a/src/views/demo/upload.vue +++ b/src/views/demo/upload.vue @@ -15,7 +15,8 @@ {{ picUrl }} - + + @@ -42,8 +43,11 @@