|
@@ -1,36 +1,35 @@
|
|
|
-<!--
|
|
|
- 多图上传组件
|
|
|
- @author: youlaitech
|
|
|
- @date 2022/11/20
|
|
|
--->
|
|
|
-
|
|
|
<template>
|
|
|
- <el-upload
|
|
|
- v-model:file-list="fileList"
|
|
|
- list-type="picture-card"
|
|
|
- :before-upload="handleBeforeUpload"
|
|
|
- :http-request="handleUpload"
|
|
|
- :on-remove="handleRemove"
|
|
|
- :on-preview="previewImg"
|
|
|
- :limit="props.limit"
|
|
|
- >
|
|
|
- <i-ep-plus />
|
|
|
- </el-upload>
|
|
|
+ <div class="upload-container">
|
|
|
+ <el-upload
|
|
|
+ v-model:file-list="fileList"
|
|
|
+ :before-upload="handleBeforeUpload"
|
|
|
+ :http-request="handleUpload"
|
|
|
+ :limit="limit"
|
|
|
+ :show-file-list="false"
|
|
|
+ class="img-box"
|
|
|
+ list-type="picture-card"
|
|
|
+ >
|
|
|
+ <i-ep-plus />
|
|
|
+ </el-upload>
|
|
|
+ <div v-for="(item, index) in fileList" :key="index" class="img-container">
|
|
|
+ <img :src="item.url" class="img-box" object-fit="cover" />
|
|
|
+ <Delete class="delete-icon" @click="deleteImg(index)" />
|
|
|
+ </div>
|
|
|
+ </div>
|
|
|
|
|
|
<el-dialog v-model="dialogVisible">
|
|
|
- <img w-full :src="previewImgUrl" alt="Preview Image" />
|
|
|
+ <img :src="previewImgUrl" alt="Preview Image" w-full />
|
|
|
</el-dialog>
|
|
|
</template>
|
|
|
|
|
|
-<script setup lang="ts">
|
|
|
+<script lang="ts" setup>
|
|
|
import {
|
|
|
UploadRawFile,
|
|
|
UploadRequestOptions,
|
|
|
UploadUserFile,
|
|
|
- UploadFile,
|
|
|
- UploadProps,
|
|
|
} from "element-plus";
|
|
|
-import { uploadFileApi, deleteFileApi } from "@/api/file";
|
|
|
+import { Delete } from "@element-plus/icons-vue";
|
|
|
+import { uploadFileApi } from "@/api/file";
|
|
|
|
|
|
const emit = defineEmits(["update:modelValue"]);
|
|
|
|
|
@@ -55,26 +54,7 @@ const previewImgUrl = ref("");
|
|
|
const dialogVisible = ref(false);
|
|
|
|
|
|
const fileList = ref([] as UploadUserFile[]);
|
|
|
-watch(
|
|
|
- () => props.modelValue,
|
|
|
- (newVal: string[]) => {
|
|
|
- const filePaths = fileList.value.map((file) => file.url);
|
|
|
- // 监听modelValue文件集合值未变化时,跳过赋值
|
|
|
- if (
|
|
|
- filePaths.length > 0 &&
|
|
|
- filePaths.length === newVal.length &&
|
|
|
- filePaths.every((x) => newVal.some((y) => y === x)) &&
|
|
|
- newVal.every((y) => filePaths.some((x) => x === y))
|
|
|
- ) {
|
|
|
- return;
|
|
|
- }
|
|
|
-
|
|
|
- fileList.value = newVal.map((filePath) => {
|
|
|
- return { url: filePath } as UploadUserFile;
|
|
|
- });
|
|
|
- },
|
|
|
- { immediate: true }
|
|
|
-);
|
|
|
+const urlList = ref([] as string[]); // 上传成功后的图片路径集合,要传给父组件
|
|
|
|
|
|
/**
|
|
|
* 自定义图片上传
|
|
@@ -83,39 +63,9 @@ watch(
|
|
|
*/
|
|
|
async function handleUpload(options: UploadRequestOptions): Promise<any> {
|
|
|
// 上传API调用
|
|
|
- const { data: fileInfo } = await uploadFileApi(options.file);
|
|
|
-
|
|
|
- // 上传成功需手动替换文件路径为远程URL,否则图片地址为预览地址 blob:http://
|
|
|
- const fileIndex = fileList.value.findIndex(
|
|
|
- (file) => file.uid == (options.file as any).uid
|
|
|
- );
|
|
|
-
|
|
|
- fileList.value.splice(fileIndex, 1, {
|
|
|
- name: fileInfo.name,
|
|
|
- url: fileInfo.url,
|
|
|
- } as UploadUserFile);
|
|
|
-
|
|
|
- emit(
|
|
|
- "update:modelValue",
|
|
|
- fileList.value.map((file) => file.url)
|
|
|
- );
|
|
|
-}
|
|
|
-
|
|
|
-/**
|
|
|
- * 删除图片
|
|
|
- */
|
|
|
-function handleRemove(removeFile: UploadFile) {
|
|
|
- const filePath = removeFile.url;
|
|
|
-
|
|
|
- if (filePath) {
|
|
|
- deleteFileApi(filePath).then(() => {
|
|
|
- // 删除成功回调
|
|
|
- emit(
|
|
|
- "update:modelValue",
|
|
|
- fileList.value.map((file) => file.url)
|
|
|
- );
|
|
|
- });
|
|
|
- }
|
|
|
+ const res: any = await uploadFileApi(options.file);
|
|
|
+ urlList.value.push(res.data.fileUrl);
|
|
|
+ emit("update:modelValue", urlList.value);
|
|
|
}
|
|
|
|
|
|
/**
|
|
@@ -129,11 +79,49 @@ function handleBeforeUpload(file: UploadRawFile) {
|
|
|
return true;
|
|
|
}
|
|
|
|
|
|
+const deleteImg = (index: number) => {
|
|
|
+ fileList.value.splice(index, 1);
|
|
|
+ urlList.value.splice(index, 1);
|
|
|
+ emit("update:modelValue", urlList.value);
|
|
|
+};
|
|
|
+
|
|
|
/**
|
|
|
* 预览图片
|
|
|
*/
|
|
|
-const previewImg: UploadProps["onPreview"] = (uploadFile) => {
|
|
|
- previewImgUrl.value = uploadFile.url!;
|
|
|
- dialogVisible.value = true;
|
|
|
-};
|
|
|
+// const previewImg: UploadProps["onPreview"] = (uploadFile) => {
|
|
|
+// previewImgUrl.value = uploadFile.url!;
|
|
|
+// dialogVisible.value = true;
|
|
|
+// };
|
|
|
</script>
|
|
|
+
|
|
|
+<style lang="scss" scoped>
|
|
|
+.upload-container {
|
|
|
+ display: flex;
|
|
|
+ justify-content: start;
|
|
|
+ flex-wrap: wrap;
|
|
|
+}
|
|
|
+
|
|
|
+.img-container {
|
|
|
+ position: relative;
|
|
|
+}
|
|
|
+
|
|
|
+.img-box {
|
|
|
+ width: 148px;
|
|
|
+ height: 148px;
|
|
|
+ display: block;
|
|
|
+ margin-right: 10px;
|
|
|
+ margin-top: 10px;
|
|
|
+ border-radius: 4px;
|
|
|
+}
|
|
|
+
|
|
|
+.delete-icon {
|
|
|
+ position: absolute;
|
|
|
+ width: 20px;
|
|
|
+ height: 20px;
|
|
|
+ left: 50%;
|
|
|
+ top: 50%;
|
|
|
+ transform: translate(-50%, -50%);
|
|
|
+ color: red;
|
|
|
+ cursor: pointer;
|
|
|
+}
|
|
|
+</style>
|