<template>
|
<view class="common-upload">
|
<u-upload
|
:fileList="internalFileList"
|
@afterRead="afterRead"
|
@delete="deleteFile"
|
:name="name"
|
:multiple="multiple"
|
:maxCount="maxCount"
|
:accept="accept"
|
:disabled="disabled"
|
></u-upload>
|
</view>
|
</template>
|
|
<script setup>
|
import { ref, watch, onMounted } from 'vue';
|
import { getToken } from "@/utils/auth";
|
import config from "@/config";
|
|
const props = defineProps({
|
// 父组件传入的文件列表(对应后端存储的对象列表)
|
modelValue: {
|
type: Array,
|
default: () => []
|
},
|
// 最大上传数量
|
maxCount: {
|
type: Number,
|
default: 9
|
},
|
// 是否支持多选
|
multiple: {
|
type: Boolean,
|
default: true
|
},
|
// 接受的文件类型
|
accept: {
|
type: String,
|
default: 'image'
|
},
|
// 上传接口对应的参数名
|
name: {
|
type: String,
|
default: 'file'
|
},
|
// 是否禁用
|
disabled: {
|
type: Boolean,
|
default: false
|
}
|
});
|
|
const emit = defineEmits(['update:modelValue']);
|
|
// 用于 u-upload 显示的内部列表
|
const internalFileList = ref([]);
|
|
// 监听外部 modelValue 变化,同步到内部显示列表
|
watch(() => props.modelValue, (newVal) => {
|
if (newVal) {
|
internalFileList.value = newVal.map(item => ({
|
...item,
|
url: item.url || item.previewURL,
|
status: 'success',
|
message: ''
|
}));
|
}
|
}, { immediate: true, deep: true });
|
|
const showToast = (message) => {
|
uni.showToast({
|
title: message,
|
icon: "none",
|
});
|
};
|
|
// 上传逻辑
|
const uploadFilePromise = (url) => {
|
return new Promise((resolve, reject) => {
|
uni.uploadFile({
|
url: config.baseUrl + "/common/upload",
|
filePath: url,
|
name: "files", // 注意:这里根据原代码是 "files"
|
header: {
|
Authorization: "Bearer " + getToken(),
|
},
|
success: (res) => {
|
try {
|
const data = JSON.parse(res.data);
|
if (data.code === 200) {
|
// 如果返回的是数组,取第一个元素
|
const resultData = Array.isArray(data.data) ? data.data[0] : data.data;
|
|
// 处理 url 赋值
|
if (!resultData.url && resultData.previewURL) {
|
resultData.url = resultData.previewURL;
|
}
|
// 兼容原代码中的 name 赋值
|
if (!resultData.name && resultData.originalFilename) {
|
resultData.name = resultData.originalFilename;
|
}
|
|
resolve(resultData);
|
} else {
|
reject(data.msg || "上传失败");
|
}
|
} catch (e) {
|
reject("解析响应失败");
|
}
|
},
|
fail: (err) => {
|
reject(err);
|
},
|
});
|
});
|
};
|
|
// 上传后的处理
|
const afterRead = async (event) => {
|
let lists = [].concat(event.file);
|
let currentModelValue = [...props.modelValue];
|
|
// 先在内部列表中添加占位(上传中状态)
|
lists.forEach(item => {
|
internalFileList.value.push({
|
...item,
|
status: 'uploading',
|
message: '上传中'
|
});
|
});
|
|
for (let i = 0; i < lists.length; i++) {
|
try {
|
const result = await uploadFilePromise(lists[i].url);
|
|
// 更新 modelValue
|
currentModelValue.push(result);
|
emit('update:modelValue', currentModelValue);
|
|
} catch (e) {
|
// 如果上传失败,从内部列表中移除刚才添加的项
|
const errorIndex = internalFileList.value.findIndex(item => item.status === 'uploading');
|
if (errorIndex > -1) {
|
internalFileList.value.splice(errorIndex, 1);
|
}
|
showToast(typeof e === "string" ? e : "上传失败");
|
}
|
}
|
};
|
|
// 删除处理
|
const deleteFile = (event) => {
|
const newList = [...props.modelValue];
|
newList.splice(event.index, 1);
|
emit('update:modelValue', newList);
|
};
|
</script>
|
|
<style scoped lang="scss">
|
.common-upload {
|
width: 100%;
|
}
|
</style>
|