2025-03-17 17:32:59 +08:00
|
|
|
<template>
|
2025-03-21 16:15:46 +08:00
|
|
|
<section class="custom_attrs_upload_content_lx" :style="{ '--columns': props.fileNum, padding: props.type == 'view' ? '20px 0' : '0px' }">
|
2025-03-17 17:32:59 +08:00
|
|
|
<el-upload
|
|
|
|
v-if="props.type != 'view' && props.upBtn"
|
|
|
|
class="custom-form__uploader"
|
|
|
|
action=""
|
|
|
|
:show-file-list="false"
|
|
|
|
:accept="props.accept"
|
|
|
|
:limit="props.limit"
|
|
|
|
:http-request="rowUploadPicture"
|
|
|
|
:disabled="attrs_.length >= props.limit"
|
|
|
|
>
|
|
|
|
<el-icon class="custom-form__uploader__icon"><Plus /></el-icon>
|
|
|
|
</el-upload>
|
|
|
|
<div v-for="(item, i) in attrs_" :key="`attr_${item.uid}`" class="attrs_content__item">
|
|
|
|
<img :src="item.url" :alt="item.name" @click="handlePreview(i)" />
|
|
|
|
<el-icon v-if="props.type != 'view'" class="clear_btn" @click.stop="handleClearAttr(item.uid)"><CircleCloseFilled /></el-icon>
|
|
|
|
</div>
|
|
|
|
<el-image-viewer v-if="previewShow" :url-list="srcList" :initial-index="index" @close="previewShow = false" />
|
|
|
|
</section>
|
|
|
|
</template>
|
|
|
|
<script setup>
|
|
|
|
import { nextTick, ref, watch } from 'vue';
|
|
|
|
import { CommonUpload } from '@/apis';
|
|
|
|
|
|
|
|
const emit = defineEmits(['update:attrs']);
|
|
|
|
const props = defineProps({
|
|
|
|
accept: {
|
|
|
|
type: String,
|
|
|
|
default: 'image/*',
|
|
|
|
},
|
|
|
|
type: {
|
|
|
|
type: String,
|
|
|
|
default: 'view',
|
|
|
|
},
|
|
|
|
attrs: {
|
|
|
|
type: Array,
|
|
|
|
default: () => [],
|
|
|
|
},
|
|
|
|
limit: {
|
|
|
|
type: Number,
|
2025-03-21 16:15:46 +08:00
|
|
|
default: 5,
|
2025-03-17 17:32:59 +08:00
|
|
|
},
|
|
|
|
fileNum: {
|
|
|
|
type: Number,
|
|
|
|
default: 4,
|
|
|
|
},
|
|
|
|
upBtn: {
|
|
|
|
type: Boolean,
|
|
|
|
default: true,
|
|
|
|
},
|
|
|
|
});
|
|
|
|
const attrs_ = ref([]);
|
|
|
|
const srcList = ref([]);
|
|
|
|
watch(
|
|
|
|
() => props.attrs,
|
|
|
|
(val) => {
|
|
|
|
attrs_.value = val;
|
|
|
|
srcList.value = attrs_.value.map((item) => item.url);
|
|
|
|
},
|
|
|
|
{ deep: true, immediate: true }
|
|
|
|
);
|
|
|
|
const index = ref(0);
|
|
|
|
const previewShow = ref(false);
|
|
|
|
function handleClearAttr(uid) {
|
|
|
|
attrs_.value = attrs_.value.filter((item) => item.uid !== uid);
|
|
|
|
emit('update:attrs', attrs_.value);
|
|
|
|
}
|
|
|
|
async function rowUploadPicture({ file }) {
|
|
|
|
const formData = new FormData();
|
|
|
|
formData.append('file', file);
|
|
|
|
const res = await CommonUpload(formData);
|
|
|
|
if (res.code === 200) {
|
|
|
|
attrs_.value.push({
|
|
|
|
...res.data,
|
|
|
|
uid: 'id_' + Date.now(),
|
|
|
|
});
|
|
|
|
emit('update:attrs', attrs_.value);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
function handlePreview(i) {
|
|
|
|
previewShow.value = false;
|
|
|
|
nextTick(() => {
|
|
|
|
index.value = i;
|
|
|
|
previewShow.value = true;
|
|
|
|
});
|
|
|
|
}
|
|
|
|
</script>
|
|
|
|
<style lang="scss">
|
|
|
|
.custom_attrs_upload_content_lx {
|
|
|
|
display: grid;
|
|
|
|
flex-wrap: wrap;
|
|
|
|
grid-template-columns: repeat(var(--columns), 1fr);
|
|
|
|
box-sizing: border-box;
|
|
|
|
gap: 20px;
|
|
|
|
> div {
|
|
|
|
width: 100%;
|
|
|
|
height: 100%;
|
|
|
|
aspect-ratio: 1 / 1;
|
|
|
|
box-sizing: border-box;
|
|
|
|
}
|
|
|
|
.attrs_content__item {
|
|
|
|
aspect-ratio: 1 / 1;
|
|
|
|
box-sizing: border-box;
|
|
|
|
position: relative;
|
|
|
|
padding: 6px;
|
|
|
|
border: 1px solid #ccc;
|
|
|
|
border-radius: 4px;
|
|
|
|
img,
|
|
|
|
video {
|
|
|
|
vertical-align: middle;
|
|
|
|
width: 100%;
|
|
|
|
height: 100%;
|
|
|
|
border-radius: 2px;
|
|
|
|
}
|
|
|
|
.clear_btn {
|
|
|
|
position: absolute;
|
|
|
|
right: 0px;
|
|
|
|
top: 0px;
|
|
|
|
font-size: 18px;
|
|
|
|
color: #f15c5c;
|
|
|
|
opacity: 0;
|
|
|
|
cursor: pointer;
|
|
|
|
background-color: #fff;
|
|
|
|
border-radius: 50%;
|
|
|
|
}
|
|
|
|
&:hover {
|
|
|
|
.clear_btn {
|
|
|
|
opacity: 1;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
</style>
|