2025-06-12 17:06:06 +08:00
|
|
|
|
<template>
|
|
|
|
|
<div class="file-uploader">
|
|
|
|
|
<el-upload
|
|
|
|
|
class="file-uploader__upload"
|
|
|
|
|
:http-request="customUploadRequest"
|
|
|
|
|
:on-success="handleUploadSuccess"
|
|
|
|
|
:on-remove="handleRemove"
|
|
|
|
|
:file-list="fileList"
|
|
|
|
|
list-type="picture-card"
|
|
|
|
|
:limit="limit"
|
|
|
|
|
:show-file-list="true"
|
|
|
|
|
:auto-upload="true"
|
|
|
|
|
:disabled="readonly"
|
|
|
|
|
:accept="accept"
|
2025-06-13 09:08:48 +08:00
|
|
|
|
@preview="handlePreview"
|
2025-06-12 17:06:06 +08:00
|
|
|
|
>
|
|
|
|
|
<el-icon v-if="fileList.length < limit"><Plus /></el-icon>
|
|
|
|
|
</el-upload>
|
|
|
|
|
<el-image-viewer v-if="previewShow" :url-list="previewList" :initial-index="previewIndex" @close="previewShow = false" />
|
|
|
|
|
</div>
|
|
|
|
|
</template>
|
|
|
|
|
|
|
|
|
|
<script setup>
|
|
|
|
|
import { ref, computed } from 'vue';
|
|
|
|
|
import { Plus } from '@element-plus/icons-vue';
|
|
|
|
|
import { CommonUpload } from '@/apis/index';
|
|
|
|
|
|
2025-06-13 09:08:48 +08:00
|
|
|
|
// 1. props & emit
|
2025-06-12 17:06:06 +08:00
|
|
|
|
const props = defineProps({
|
2025-06-13 09:08:48 +08:00
|
|
|
|
modelValue: { type: [Array, String], default: () => [] },
|
|
|
|
|
ossUrl: { type: String, default: 'http://gov-cloud.oss-cn-chengdu.aliyuncs.com/' },
|
|
|
|
|
limit: { type: Number, default: 5 },
|
|
|
|
|
accept: { type: String, default: 'image/*' },
|
|
|
|
|
readonly: { type: Boolean, default: false },
|
|
|
|
|
});
|
|
|
|
|
const emit = defineEmits(['update:modelValue']);
|
|
|
|
|
|
|
|
|
|
// 2. 中间层 computed:统一成数组,写时根据 limit 决定发出数组还是字符串
|
|
|
|
|
const selectedFiles = computed({
|
|
|
|
|
get() {
|
|
|
|
|
// 回显:如果父传字符串且 limit===1,就把它当成长度 1 数组
|
|
|
|
|
if (props.limit === 1 && typeof props.modelValue === 'string' && props.modelValue) {
|
|
|
|
|
return [props.modelValue];
|
|
|
|
|
}
|
|
|
|
|
// 其他情况,确保数组
|
|
|
|
|
return Array.isArray(props.modelValue) ? props.modelValue : [];
|
2025-06-12 17:06:06 +08:00
|
|
|
|
},
|
2025-06-13 09:08:48 +08:00
|
|
|
|
set(val) {
|
|
|
|
|
// 内部操作后:如果单文件场景,传字符串;多文件场景,传数组
|
|
|
|
|
if (props.limit === 1) {
|
|
|
|
|
emit('update:modelValue', val.length ? val[0] : '');
|
|
|
|
|
} else {
|
|
|
|
|
emit('update:modelValue', val);
|
|
|
|
|
}
|
2025-06-12 17:06:06 +08:00
|
|
|
|
},
|
|
|
|
|
});
|
|
|
|
|
|
2025-06-13 09:08:48 +08:00
|
|
|
|
// 3. fileList & previewList 都基于 selectedFiles
|
|
|
|
|
const fileList = computed(() =>
|
|
|
|
|
selectedFiles.value.map((path, idx) => ({
|
|
|
|
|
name: `file_${idx}`,
|
2025-06-12 17:06:06 +08:00
|
|
|
|
url: props.ossUrl + path,
|
|
|
|
|
uid: `${idx}`,
|
2025-06-13 09:08:48 +08:00
|
|
|
|
}))
|
|
|
|
|
);
|
2025-06-12 17:06:06 +08:00
|
|
|
|
const previewShow = ref(false);
|
|
|
|
|
const previewIndex = ref(0);
|
2025-06-13 09:08:48 +08:00
|
|
|
|
const previewList = computed(() => fileList.value.map((f) => f.url));
|
2025-06-12 17:06:06 +08:00
|
|
|
|
|
2025-06-13 09:08:48 +08:00
|
|
|
|
// 4. 上传 & 移除
|
2025-06-12 17:06:06 +08:00
|
|
|
|
const customUploadRequest = async ({ file, onSuccess, onError }) => {
|
|
|
|
|
const formData = new FormData();
|
|
|
|
|
formData.append('file', file);
|
|
|
|
|
try {
|
|
|
|
|
const res = await CommonUpload(formData);
|
|
|
|
|
onSuccess(res, file);
|
|
|
|
|
} catch (err) {
|
|
|
|
|
onError(err);
|
|
|
|
|
}
|
|
|
|
|
};
|
|
|
|
|
function handleUploadSuccess(res) {
|
|
|
|
|
const relative = res.data?.url;
|
2025-06-13 09:08:48 +08:00
|
|
|
|
if (!relative) return;
|
|
|
|
|
// 推入中间层
|
|
|
|
|
selectedFiles.value = [...selectedFiles.value, relative];
|
2025-06-12 17:06:06 +08:00
|
|
|
|
}
|
|
|
|
|
function handleRemove(file) {
|
2025-06-13 09:08:48 +08:00
|
|
|
|
const rel = file.url.replace(props.ossUrl, '');
|
|
|
|
|
selectedFiles.value = selectedFiles.value.filter((p) => p !== rel);
|
2025-06-12 17:06:06 +08:00
|
|
|
|
}
|
|
|
|
|
|
2025-06-13 09:08:48 +08:00
|
|
|
|
// 5. 预览
|
2025-06-12 17:06:06 +08:00
|
|
|
|
function handlePreview(file) {
|
|
|
|
|
const idx = fileList.value.findIndex((item) => item.uid === file.uid);
|
2025-06-13 09:08:48 +08:00
|
|
|
|
if (idx >= 0) {
|
2025-06-12 17:06:06 +08:00
|
|
|
|
previewIndex.value = idx;
|
|
|
|
|
previewShow.value = true;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
</script>
|
|
|
|
|
|
|
|
|
|
<style scoped>
|
|
|
|
|
.file-uploader {
|
|
|
|
|
display: flex;
|
|
|
|
|
flex-wrap: wrap;
|
|
|
|
|
}
|
|
|
|
|
.file-uploader__upload {
|
|
|
|
|
margin-right: 16px;
|
|
|
|
|
}
|
|
|
|
|
</style>
|