refactor: ♻️ 图片上传组件重构
This commit is contained in:
@@ -4,14 +4,13 @@
|
|||||||
<div style="display: none">
|
<div style="display: none">
|
||||||
<el-upload
|
<el-upload
|
||||||
ref="uploadRef"
|
ref="uploadRef"
|
||||||
v-model:file-list="fileList"
|
:file-list="fileList"
|
||||||
|
:http-request="handleUpload"
|
||||||
:before-upload="handleBeforeUpload"
|
:before-upload="handleBeforeUpload"
|
||||||
:action="props.action"
|
:on-success="handleSuccess"
|
||||||
:headers="props.headers"
|
|
||||||
:data="props.data"
|
|
||||||
:name="props.name"
|
|
||||||
:on-success="handleSuccessFile"
|
|
||||||
:on-error="handleError"
|
:on-error="handleError"
|
||||||
|
:data="props.additionalParams"
|
||||||
|
:name="props.fileParamName"
|
||||||
:accept="props.accept"
|
:accept="props.accept"
|
||||||
:limit="props.limit"
|
:limit="props.limit"
|
||||||
/>
|
/>
|
||||||
@@ -47,48 +46,21 @@
|
|||||||
v-if="viewVisible"
|
v-if="viewVisible"
|
||||||
:zoom-rate="1.2"
|
:zoom-rate="1.2"
|
||||||
:initialIndex="initialIndex"
|
:initialIndex="initialIndex"
|
||||||
:url-list="viewFileList"
|
:url-list="previewImgUrls"
|
||||||
@close="closePreview"
|
@close="closePreview"
|
||||||
/>
|
/>
|
||||||
</template>
|
</template>
|
||||||
<script setup lang="ts">
|
<script setup lang="ts">
|
||||||
import { UploadRawFile, UploadUserFile, UploadFile } from "element-plus";
|
import { UploadRawFile, UploadUserFile, UploadRequestOptions } from "element-plus";
|
||||||
import FileAPI from "@/api/file";
|
import FileAPI, { FileInfo } from "@/api/file";
|
||||||
import { getToken } from "@/utils/auth";
|
|
||||||
import { ResultEnum } from "@/enums/ResultEnum";
|
|
||||||
|
|
||||||
const emit = defineEmits(["update:modelValue", "change"]);
|
const emit = defineEmits(["update:modelValue"]);
|
||||||
|
|
||||||
const props = defineProps({
|
const props = defineProps({
|
||||||
/**
|
/**
|
||||||
* 文件路径集合
|
* 附加的参数
|
||||||
*/
|
*/
|
||||||
modelValue: {
|
additionalParams: {
|
||||||
type: [Array, String],
|
|
||||||
default: () => [],
|
|
||||||
},
|
|
||||||
/**
|
|
||||||
* 上传地址
|
|
||||||
*/
|
|
||||||
action: {
|
|
||||||
type: String,
|
|
||||||
default: FileAPI.uploadUrl,
|
|
||||||
},
|
|
||||||
/**
|
|
||||||
* 请求头
|
|
||||||
*/
|
|
||||||
headers: {
|
|
||||||
type: Object,
|
|
||||||
default: () => {
|
|
||||||
return {
|
|
||||||
Authorization: getToken(),
|
|
||||||
};
|
|
||||||
},
|
|
||||||
},
|
|
||||||
/**
|
|
||||||
* 请求携带的额外参数
|
|
||||||
*/
|
|
||||||
data: {
|
|
||||||
type: Object,
|
type: Object,
|
||||||
default: () => {
|
default: () => {
|
||||||
return {};
|
return {};
|
||||||
@@ -97,7 +69,7 @@ const props = defineProps({
|
|||||||
/**
|
/**
|
||||||
* 上传文件的参数名
|
* 上传文件的参数名
|
||||||
*/
|
*/
|
||||||
name: {
|
fileParamName: {
|
||||||
type: String,
|
type: String,
|
||||||
default: "file",
|
default: "file",
|
||||||
},
|
},
|
||||||
@@ -145,13 +117,6 @@ const props = defineProps({
|
|||||||
default: () => [],
|
default: () => [],
|
||||||
},
|
},
|
||||||
|
|
||||||
/**
|
|
||||||
* 是否同步删除
|
|
||||||
*/
|
|
||||||
isSyncDelete: {
|
|
||||||
type: Boolean,
|
|
||||||
default: true,
|
|
||||||
},
|
|
||||||
/**
|
/**
|
||||||
* 自定义样式
|
* 自定义样式
|
||||||
*/
|
*/
|
||||||
@@ -164,108 +129,60 @@ const props = defineProps({
|
|||||||
};
|
};
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 是否多图上传
|
||||||
|
*/
|
||||||
|
multiple: {
|
||||||
|
type: Boolean,
|
||||||
|
default: false,
|
||||||
|
},
|
||||||
|
});
|
||||||
|
|
||||||
|
// 定义v-model
|
||||||
|
const modelValue = defineModel("modelValue", {
|
||||||
|
type: [String, Array] as PropType<string | string[]>,
|
||||||
|
required: true,
|
||||||
|
default: () => "",
|
||||||
});
|
});
|
||||||
|
|
||||||
const viewVisible = ref(false);
|
const viewVisible = ref(false);
|
||||||
const initialIndex = ref(0);
|
const initialIndex = ref(0);
|
||||||
|
|
||||||
const fileList = ref([] as UploadUserFile[]);
|
const fileList = ref<UploadUserFile[]>([]); // 默认上传文件
|
||||||
const valFileList = ref([] as string[]);
|
const previewImgUrls = ref<string[]>([]);
|
||||||
const viewFileList = ref([] as string[]);
|
|
||||||
|
|
||||||
// 添加一个ref来引用el-upload组件
|
// 添加一个ref来引用el-upload组件
|
||||||
const uploadRef = ref();
|
const uploadRef = ref();
|
||||||
|
|
||||||
watch(
|
watch(
|
||||||
() => props.modelValue,
|
() => modelValue.value,
|
||||||
(newVal) => {
|
(newValue) => {
|
||||||
if (typeof newVal === "string" && !newVal) {
|
if (!props.multiple) {
|
||||||
fileList.value = [];
|
|
||||||
viewFileList.value = [];
|
|
||||||
valFileList.value = [];
|
|
||||||
return;
|
return;
|
||||||
|
} else {
|
||||||
|
if (Array.isArray(newValue)) {
|
||||||
|
fileList.value = newValue.map((filePath) => {
|
||||||
|
return { url: filePath } as UploadUserFile;
|
||||||
|
});
|
||||||
|
}
|
||||||
}
|
}
|
||||||
const modelValue = typeof newVal === "string" ? [newVal] : (newVal as string[]);
|
|
||||||
const filePaths = fileList.value.map((file) => file.url);
|
|
||||||
// 监听modelValue文件集合值未变化时,跳过赋值
|
|
||||||
if (
|
|
||||||
filePaths.length > 0 &&
|
|
||||||
filePaths.length === modelValue.length &&
|
|
||||||
filePaths.every((x) => modelValue.some((y) => y === x)) &&
|
|
||||||
modelValue.every((y) => filePaths.some((x) => x === y))
|
|
||||||
) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!modelValue || modelValue.length <= 0) {
|
|
||||||
fileList.value = [];
|
|
||||||
viewFileList.value = [];
|
|
||||||
valFileList.value = [];
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
fileList.value = modelValue.map((filePath) => {
|
|
||||||
return { url: filePath } as UploadUserFile;
|
|
||||||
});
|
|
||||||
valFileList.value = modelValue;
|
|
||||||
},
|
},
|
||||||
{ immediate: true }
|
{ immediate: true }
|
||||||
);
|
);
|
||||||
|
|
||||||
/**
|
|
||||||
* 上传成功回调
|
|
||||||
*
|
|
||||||
* @param options
|
|
||||||
*/
|
|
||||||
const handleSuccessFile = (response: any, file: UploadFile) => {
|
|
||||||
if (response.code === ResultEnum.SUCCESS) {
|
|
||||||
ElMessage.success("上传成功");
|
|
||||||
valFileList.value.push(response.data.url);
|
|
||||||
if (props.limit === 1) {
|
|
||||||
emit("update:modelValue", response.data.url);
|
|
||||||
emit("change", response.data.url);
|
|
||||||
} else {
|
|
||||||
emit("update:modelValue", valFileList.value);
|
|
||||||
emit("change", valFileList.value);
|
|
||||||
}
|
|
||||||
return;
|
|
||||||
} else {
|
|
||||||
ElMessage.error(response.msg || "上传失败");
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
const handleError = (error: any) => {
|
|
||||||
ElMessage.error("上传失败");
|
|
||||||
};
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 删除图片
|
* 删除图片
|
||||||
*/
|
*/
|
||||||
function handleRemove(path: string) {
|
function handleRemove(path: string) {
|
||||||
if (path) {
|
if (path) {
|
||||||
if (props.isSyncDelete) {
|
FileAPI.deleteByPath(path).then(() => {
|
||||||
FileAPI.deleteByPath(path).then(() => {
|
if (Array.isArray(modelValue.value)) {
|
||||||
valFileList.value = valFileList.value.filter((x) => x !== path);
|
modelValue.value = modelValue.value.filter((x) => x !== path);
|
||||||
// 删除成功回调
|
|
||||||
if (props.limit === 1) {
|
|
||||||
emit("update:modelValue", "");
|
|
||||||
emit("change", "");
|
|
||||||
} else {
|
|
||||||
emit("update:modelValue", valFileList.value);
|
|
||||||
emit("change", valFileList.value);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
} else {
|
|
||||||
valFileList.value = valFileList.value.filter((x) => x !== path);
|
|
||||||
// 删除成功回调
|
|
||||||
if (props.limit === 1) {
|
|
||||||
emit("update:modelValue", "");
|
|
||||||
emit("change", "");
|
|
||||||
} else {
|
} else {
|
||||||
emit("update:modelValue", valFileList.value);
|
modelValue.value = "";
|
||||||
emit("change", valFileList.value);
|
|
||||||
}
|
}
|
||||||
}
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -303,11 +220,65 @@ function handleBeforeUpload(file: UploadRawFile) {
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* 上传文件
|
||||||
|
*/
|
||||||
|
function handleUpload(options: UploadRequestOptions) {
|
||||||
|
return new Promise((resolve, reject) => {
|
||||||
|
const { file, onSuccess, onError } = options;
|
||||||
|
|
||||||
|
const formData = new FormData();
|
||||||
|
formData.append(props.fileParamName, file);
|
||||||
|
|
||||||
|
// 处理附加参数
|
||||||
|
Object.keys(props.additionalParams).forEach((key) => {
|
||||||
|
formData.append(key, props.additionalParams[key]);
|
||||||
|
});
|
||||||
|
|
||||||
|
FileAPI.upload(formData)
|
||||||
|
.then((data) => {
|
||||||
|
onSuccess(data);
|
||||||
|
resolve(data);
|
||||||
|
})
|
||||||
|
.catch((error) => {
|
||||||
|
onError(error);
|
||||||
|
reject(error);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 上传成功回调
|
||||||
|
*
|
||||||
|
* @param fileInfo 上传成功后的文件信息
|
||||||
|
*/
|
||||||
|
const handleSuccess = (fileInfo: FileInfo) => {
|
||||||
|
ElMessage.success("上传成功");
|
||||||
|
valFileList.value.push(fileInfo.url);
|
||||||
|
if (!props.multiple) {
|
||||||
|
emit("update:modelValue", fileInfo.url);
|
||||||
|
emit("change", fileInfo.url);
|
||||||
|
} else {
|
||||||
|
emit("update:modelValue", valFileList.value);
|
||||||
|
emit("change", valFileList.value);
|
||||||
|
}
|
||||||
|
return;
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 上传失败回调
|
||||||
|
*
|
||||||
|
* @param error 上传失败的错误信息
|
||||||
|
*/
|
||||||
|
const handleError = (error: any) => {
|
||||||
|
ElMessage.error("上传失败");
|
||||||
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 预览图片
|
* 预览图片
|
||||||
*/
|
*/
|
||||||
const previewImg = (path: string) => {
|
const previewImg = (path: string) => {
|
||||||
viewFileList.value = fileList.value.map((file) => file.url!);
|
previewImgUrls.value = fileList.value.map((file) => file.url!);
|
||||||
initialIndex.value = fileList.value.findIndex((file) => file.url === path);
|
initialIndex.value = fileList.value.findIndex((file) => file.url === path);
|
||||||
viewVisible.value = true;
|
viewVisible.value = true;
|
||||||
};
|
};
|
||||||
|
|||||||
Reference in New Issue
Block a user