Files
sgxt_web/src/components/MyComponents/Upload/index.vue

303 lines
7.9 KiB
Vue
Raw Normal View History

2025-04-12 14:54:02 +08:00
<template>
2025-07-19 20:33:14 +08:00
<div class="form-item-box" :class="props.showBtn ? 'showBtn-upload' : ''" :style="{ width: width }">
<el-upload v-bind="$attrs" :headers="headers" :multiple="false" class="avatar-uploader" :limit="props.limit"
:action="actionUrl" :list-type="props.showBtn ? '' : 'picture-card'" :file-list="fileList" show-file-list
:on-exceed="handleExceed" :on-success="handlerSuccess" :before-upload="beforeImgUpload">
2025-04-12 14:54:02 +08:00
<template #default>
2025-07-19 17:08:53 +08:00
<el-button v-if="props.showBtn" size="small" type="primary">上传文件</el-button>
2025-08-16 16:54:03 +08:00
<el-icon v-else>
<Plus />
</el-icon>
2025-04-12 14:54:02 +08:00
</template>
2025-07-05 12:03:00 +08:00
<template #file="{ file }" v-if="!props.showBtn">
2025-04-12 14:54:02 +08:00
<div v-if="props.isImg">
<img class="el-upload-list__item-thumbnail" :src="file.url" alt="" />
<span class="el-upload-list__item-actions">
2025-09-24 17:43:52 +08:00
<span class="el-upload-list__item-preview" @click="handlePictureCardPreview(file)"><el-icon> <zoom-in /></el-icon></span>
<span v-if="!disabled" class="el-upload-list__item-delete" @click="handleRemove(file, fileList)"><el-icon><Delete /></el-icon></span>
2025-04-12 14:54:02 +08:00
</span>
</div>
<div v-else>
<div class="file-wrap">
2025-07-19 20:33:14 +08:00
<span><svg-icon :icon="getSuffix(file.name)" /></span>
2025-04-12 14:54:02 +08:00
<span class="file-name">{{ file.name }}</span>
</div>
<span class="el-upload-list__item-actions">
2025-07-19 20:33:14 +08:00
<span v-if="!disabled" class="el-upload-list__item-delete" @click="handleDownload(file)">
2025-08-16 16:54:03 +08:00
<el-icon>
<Download />
</el-icon>
2025-04-12 14:54:02 +08:00
</span>
2025-07-19 20:33:14 +08:00
<span v-if="!disabled" class="el-upload-list__item-delete" @click="handleRemove(file, fileList)">
2025-08-16 16:54:03 +08:00
<el-icon>
<Delete />
</el-icon>
2025-04-12 14:54:02 +08:00
</span>
</span>
</div>
</template>
</el-upload>
<el-dialog v-model="dialogVisible">
<img style="width: 100%" :src="dialogImageUrl" alt="" />
</el-dialog>
</div>
</template>
<script setup>
import { COMPONENT_WIDTH } from "@/constant";
2025-07-10 19:51:22 +08:00
import { ref, defineProps, defineEmits, computed, watch, onMounted } from "vue";
2025-07-05 12:03:00 +08:00
import { ElMessage } from "element-plus";
2025-04-12 14:54:02 +08:00
import { useStore } from "vuex";
const props = defineProps({
//获取组件传值
modelValue: {
type: Array,
default: []
},
limit: {
type: Number,
default: 1
},
isImg: {
type: Boolean,
default: true
},
width: {
default: COMPONENT_WIDTH,
type: String
2025-07-05 12:03:00 +08:00
},
2025-07-10 19:51:22 +08:00
showBtn: {
type: Boolean,
default: false
2025-07-19 17:08:53 +08:00
},
2025-07-19 20:33:14 +08:00
isAll: {
2025-07-19 18:37:07 +08:00
type: Boolean,
default: false
}
2025-04-12 14:54:02 +08:00
});
2025-07-19 20:33:14 +08:00
const actionUrl = computed(() => {
if (props.isAll) {
return "/mosty-api/mosty-base/minio/image/upload/id";
} else {
2025-09-24 17:43:52 +08:00
return props.isImg ? "/mosty-api/mosty-base/minio/image/upload/id": "/mosty-api/mosty-base/minio/file/upload";
2025-07-19 18:37:07 +08:00
}
});
2025-04-12 14:54:02 +08:00
const emits = defineEmits(["update:modelValue", "handleChange"]);
//获取后缀
const getSuffix = (fileName) => {
let suffix = "";
try {
suffix = fileName.substr(fileName.lastIndexOf(".") + 1, 4); //截取最后一个点号后4个字符
} catch (err) {
suffix = "";
return "OTHER";
}
// fileName无后缀返回 false
if (!suffix) return "";
// 图片格式
var imglist = ["png", "jpg", "jpeg", "bmp", "gif"];
if (imglist.includes(suffix)) return "IMG";
//txt
if (suffix === "txt") return "TXT";
//excel XLS
const excelist = ["xls", "xlsx"];
if (excelist.includes(suffix)) return "XLS";
// 匹配 word
var wordlist = ["doc", "docx"];
if (wordlist.includes(suffix)) return "DOC";
//pdf
if (suffix === "pdf") return "PDF";
//视频 音频
2025-07-19 20:33:14 +08:00
var videolist = [
"mp4",
"m2v",
"mkv",
"rmvb",
"wmv",
"avi",
"flv",
"mov",
"m4v"
];
2025-04-12 14:54:02 +08:00
if (videolist.includes(suffix)) return "VIDEO";
var musiclist = ["mp3", "wav", "wmv"];
if (musiclist.includes(suffix)) return "MUSIC";
var pptlist = ["ppt", "pptx"];
if (pptlist.includes(suffix)) return "PPT";
//压缩包
var yslist = ["7z", "rar", "zip", "apz", "ar", "hpk", "hyp", "hbc2"];
if (yslist.includes(suffix)) return "YS";
//否则返回other
return "OTHER";
};
const store = useStore();
const dialogImageUrl = ref("");
const dialogVisible = ref(false);
const disabled = ref(false);
const headers = ref({
Authorization: store.getters.token
});
2025-07-10 19:51:22 +08:00
const fileList = ref([]);
watch(
() => props.modelValue,
(val) => {
let arr = val ? val : [];
if (arr && arr.length > 0) {
if (!props.sfUrl) {
2025-08-16 16:54:03 +08:00
if (Array.isArray(arr)) {
fileList.value = arr.map((el) => {
2025-07-19 20:33:14 +08:00
if (Object.prototype.toString.call(el) === "[object Object]") {
return {
url: `/mosty-api/mosty-base/minio/image/download/` + el,
name: el.name
};
} else {
2025-07-19 18:37:07 +08:00
return { url: `/mosty-api/mosty-base/minio/image/download/` + el };
}
2025-07-10 19:51:22 +08:00
});
2025-08-16 16:54:03 +08:00
} else {
const fjListData=arr.split(',')
fileList.value = fjListData.map((el) => {
if (Object.prototype.toString.call(el) === "[object Object]") {
return {
url: `/mosty-api/mosty-base/minio/image/download/` + el,
name: el.name
};
} else {
return { url: `/mosty-api/mosty-base/minio/image/download/` + el };
}
});
}
2025-07-10 19:51:22 +08:00
} else {
fileList.value = arr.map((el) => {
2025-07-19 20:33:14 +08:00
if (Object.prototype.toString.call(el) === "[object Object]") {
return { url: el, name: el.name };
} else {
return { url: el };
2025-07-19 18:37:07 +08:00
}
2025-07-10 19:51:22 +08:00
});
}
}
},
{ immediate: true }
);
2025-04-12 14:54:02 +08:00
const handlerSuccess = (res, file) => {
2025-07-19 17:08:53 +08:00
file.url = `/mosty-api/mosty-base/minio/image/download/` + res.data;
fileList.value.push(file);
let arr = props.modelValue ? props.modelValue : [];
arr.push(res.data);
emits("update:modelValue", arr);
emits("handleChange", props.modelValue);
2025-04-12 14:54:02 +08:00
};
2025-07-05 19:37:28 +08:00
2025-04-12 14:54:02 +08:00
const handleExceed = (files, fileList) => {
ElMessage.warning(`限制,只能上传${props.limit}个文件或图片`);
};
const beforeImgUpload = (file) => {
if (props.isImg) {
let isIMG = false;
if (getSuffix(file.name) === "IMG") {
isIMG = true;
}
const isLt5M = file.size / 1024 / 1024 < 5;
if (!isIMG) {
ElMessage.error("上传图片只能是jpg/png/jpeg/bmp/gif格式!");
}
if (!isLt5M) {
ElMessage.error("上传图片大小不能超过 5MB!");
}
return isIMG && isLt5M;
} else {
return true;
}
};
//查询图片
const handlePictureCardPreview = (file) => {
dialogImageUrl.value = file.url;
dialogVisible.value = true;
};
const handleDownload = (file) => {
window.open(file.response.data);
};
const handleRemove = (file) => {
let index = fileList.value.findIndex(function (item) {
return item.url === file.url;
});
fileList.value.splice(index, 1);
props.modelValue.splice(index, 1);
emits("handleChange", props.modelValue);
2025-07-05 19:37:28 +08:00
emits("update:modelValue", props.modelValue);
2025-04-12 14:54:02 +08:00
};
2025-07-10 19:51:22 +08:00
const propsModelValue = ref();
2025-04-12 14:54:02 +08:00
</script>
<style lang="scss" scoped>
.avatar-uploader .el-upload {
border: 1px dashed #d9d9d9;
border-radius: 6px;
cursor: pointer;
position: relative;
overflow: hidden;
}
.avatar-uploader .el-upload:hover {
border-color: #409eff;
}
.el-icon.avatar-uploader-icon {
font-size: 28px;
color: #8c939d;
width: 178px;
height: 178px;
text-align: center;
}
.avatar {
width: 178px;
height: 178px;
display: block;
}
.file-wrap {
display: flex;
flex-direction: column;
justify-content: center;
align-items: center;
::v-deep .svg-icon {
font-size: 48px;
margin: 28px 0 2px 0;
}
.file-name {
width: 88%;
font-size: 14px;
line-height: 22px;
text-align: center;
overflow: hidden;
/*将对象作为弹性伸缩盒子模型显示*/
display: -webkit-box;
/*设置子元素排列方式*/
-webkit-box-orient: vertical;
/*设置显示的行数,多出的部分会显示为...*/
-webkit-line-clamp: 2;
}
}
2025-08-16 16:54:03 +08:00
</style>