first commiit

This commit is contained in:
2025-02-08 10:15:06 +08:00
parent 6815bd083b
commit 262bf41379
242 changed files with 19959 additions and 1 deletions

View File

@@ -0,0 +1,203 @@
<!-- 单图上传组件 -->
<template>
<el-upload
v-model="modelValue"
class="single-upload"
list-type="picture-card"
:show-file-list="false"
:accept="props.accept"
:before-upload="handleBeforeUpload"
:http-request="handleUpload"
:on-success="onSuccess"
:on-error="onError"
multiple
>
<template #default>
<el-image v-if="modelValue" :src="modelValue" />
<el-icon v-if="modelValue" class="single-upload__delete-btn" @click.stop="handleDelete">
<CircleCloseFilled />
</el-icon>
<el-icon v-else class="single-upload__add-btn">
<Plus />
</el-icon>
</template>
</el-upload>
</template>
<script setup lang="ts">
import { UploadRawFile, UploadRequestOptions } from "element-plus";
import FileAPI, { FileInfo } from "@/api/file";
const props = defineProps({
/**
* 请求携带的额外参数
*/
data: {
type: Object,
default: () => {
return {};
},
},
/**
* 上传文件的参数名
*/
name: {
type: String,
default: "file",
},
/**
* 最大文件大小单位M
*/
maxFileSize: {
type: Number,
default: 10,
},
/**
* 上传图片格式,默认支持所有图片(image/*),指定格式示例:'.png,.jpg,.jpeg,.gif,.bmp'
*/
accept: {
type: String,
default: "image/*",
},
/**
* 自定义样式,用于设置组件的宽度和高度等其他样式
*/
style: {
type: Object,
default: () => {
return {
width: "150px",
height: "150px",
};
},
},
});
const modelValue = defineModel("modelValue", {
type: String,
required: true,
default: () => "",
});
/**
* 限制用户上传文件的格式和大小
*/
function handleBeforeUpload(file: UploadRawFile) {
// 校验文件类型:虽然 accept 属性限制了用户在文件选择器中可选的文件类型,但仍需在上传时再次校验文件实际类型,确保符合 accept 的规则
const acceptTypes = props.accept.split(",").map((type) => type.trim());
// 检查文件格式是否符合 accept
const isValidType = acceptTypes.some((type) => {
if (type === "image/*") {
// 如果是 image/*,检查 MIME 类型是否以 "image/" 开头
return file.type.startsWith("image/");
} else if (type.startsWith(".")) {
// 如果是扩展名 (.png, .jpg),检查文件名是否以指定扩展名结尾
return file.name.toLowerCase().endsWith(type);
} else {
// 如果是具体的 MIME 类型 (image/png, image/jpeg),检查是否完全匹配
return file.type === type;
}
});
if (!isValidType) {
ElMessage.warning(`上传文件的格式不正确,仅支持:${props.accept}`);
return false;
}
// 限制文件大小
if (file.size > props.maxFileSize * 1024 * 1024) {
ElMessage.warning("上传图片不能大于" + props.maxFileSize + "M");
return false;
}
return true;
}
/*
* 上传图片
*/
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]);
});
FileAPI.upload(formData)
.then((data) => {
resolve(data);
})
.catch((error) => {
reject(error);
});
});
}
/**
* 删除图片
*/
function handleDelete() {
modelValue.value = "";
}
/**
* 上传成功回调
*
* @param fileInfo 上传成功后的文件信息
*/
const onSuccess = (fileInfo: FileInfo) => {
ElMessage.success("上传成功");
modelValue.value = fileInfo.url;
};
/**
* 上传失败回调
*/
const onError = (error: any) => {
console.log("onError");
ElMessage.error("上传失败: " + error.message);
};
</script>
<style scoped lang="scss">
:deep(.el-upload--picture-card) {
/* width: var(--el-upload-picture-card-size);
height: var(--el-upload-picture-card-size); */
width: v-bind("props.style.width");
height: v-bind("props.style.height");
}
.single-upload {
position: relative;
overflow: hidden;
cursor: pointer;
border: 1px var(--el-border-color) solid;
border-radius: 5px;
&:hover {
border-color: var(--el-color-primary);
}
&__delete-btn {
position: absolute;
top: 1px;
right: 1px;
font-size: 16px;
color: #ff7901;
cursor: pointer;
background: #fff;
border-radius: 100%;
:hover {
color: #ff4500;
}
}
}
</style>