You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
shop-admin/src/components/extra/ElUploadImage.vue

213 lines
6.4 KiB

<template>
<component :is="render" />
</template>
<script setup lang="jsx">
import config from '@/configs';
import { ElMessage } from '@/plugins/element-plus';
import { ElUpload } from 'element-plus/es/components/upload/index';
import 'element-plus/es/components/upload/style/css';
import { ElImage } from 'element-plus/es/components/image/index';
import 'element-plus/es/components/image/style/css';
const store = useStore();
const props = defineProps({
action: {
type: String,
default: config.baseURL + '/edu-oss/oss/fileUpload',
},
data: {
type: Object,
default() {
return { service: 'msb-edu-course' };
},
},
headers: {
type: Object,
default() {
return {};
},
},
drag: {
type: Boolean,
default: true,
},
multiple: {
type: Boolean,
defualt: false,
},
disabled: {
type: Boolean,
defualt: false,
},
limit: {
type: Number,
default: 1,
},
size: {
type: Number,
default: 1024 * 1024 * 20,
},
accept: {
type: String,
default: '*.*',
},
});
const attrs = useAttrs();
const emits = defineEmits(['update:modelValue']);
let headers = { ...props.headers };
headers['Authorization'] = 'Bearer ' + store.state.local.token;
let imgList = ref([]);
const refsUpload = ref(null);
watch(
() => imgList,
() => {
if (props.limit === 1) {
emits('update:modelValue', unref(imgList)[0]?.response.data);
} else {
emits('update:modelValue', unref(imgList));
}
},
{ deep: true }
);
const handleSuccess = (res, file, list) => {
console.info('[upload] success', list);
imgList.value = list;
};
const handleRemove = (file, list) => {
console.info('[upload] remove', list);
imgList.value = list;
};
const handleExceed = (list) => {
console.info('[upload] exceed', list);
ElMessage.error('超出最大上传数量');
};
const handleBeforeUpload = (file) => {
console.info('[upload] upload', file);
if (file.size >= props.size) {
ElMessage.error('超出文件大小限制');
return false;
}
};
const fmtSize = computed(() => {
const units = ['byte', 'KB', 'MB', 'GB', 'TB'];
let res = props.size,
unit = 0;
while (res >= 800) {
res /= 1024;
unit++;
}
return res + units[unit];
});
watch(
() => attrs.modelValue,
(value) => {
if (props.limit === 1 && value) {
imgList.value = [
{
name: value,
response: {
data: value,
},
},
];
} else {
imgList.value = value || [];
}
},
{ immediate: true, deep: true }
);
const handleDeleteImage = (index) => {
if (unref(refsUpload)) {
unref(refsUpload).handleRemove(imgList[index]);
} else {
unref(imgList).splice(index, 1);
}
};
const render = () => (
<div class="upload-box">
<div class="upload-image">
{unref(imgList).map((item, index) => (
<div class="img-li">
<ElImage src={item?.response?.data} alt={item.name} />
{!props.disabled ? (
<div class="img-li-cover" onClick={() => handleDeleteImage(index)}>
<ElIcon class="upload-del-icon" name="delete-bin-fill" size="20" />
</div>
) : (
''
)}
</div>
))}
{props.limit !== unref(imgList).length ? (
<ElUpload
ref={refsUpload}
{...{ ...props, headers }}
{...attrs}
before-upload={handleBeforeUpload}
on-exceed={handleExceed}
on-remove={handleRemove}
on-success={handleSuccess}
show-file-list={false}
>
<ElIcon class="el-icon--upload" name="add-fill" size="20" />
</ElUpload>
) : (
''
)}
</div>
<div class="el-upload__tip">支持小于 {unref(fmtSize)} 文件</div>
</div>
);
</script>
<style lang="less" scoped>
.upload-box {
:deep(.upload-image) {
display: flex;
flex-wrap: wrap;
.img-li {
display: flex;
align-items: center;
justify-content: center;
position: relative;
width: 150px;
height: 150px;
margin-right: 20px;
overflow: hidden;
.img-li-cover {
display: none;
}
&:hover {
.img-li-cover {
display: flex;
align-items: center;
justify-content: center;
position: absolute;
top: 0;
left: 0;
width: 100%;
height: 100%;
background-color: rgba(0, 0, 0, 0.5);
cursor: pointer;
.upload-del-icon {
color: #fff;
}
}
}
}
}
}
:deep(.el-upload) {
width: 150px;
height: 150px;
.el-upload-dragger {
display: flex;
align-items: center;
justify-content: center;
width: 100%;
height: 100%;
.el-icon--upload {
margin: 0;
}
}
}
</style>