优化
This commit is contained in:
parent
e3c4c384b9
commit
3da46ccfee
201
src/components/GxUpload/index.vue
Normal file
201
src/components/GxUpload/index.vue
Normal file
@ -0,0 +1,201 @@
|
||||
<template>
|
||||
<div class="clearfix">
|
||||
<a-upload list-type="picture-card" :multiple="multiple" v-model:file-list="fileList" @preview="handlePreview"
|
||||
@change="handleChange" :customRequest="handleCustomRequest" :beforeUpload="beforeUpload">
|
||||
<div v-if="fileList.length < fileNumber">
|
||||
<plus-outlined />
|
||||
<div class="ant-upload-text">上传</div>
|
||||
</div>
|
||||
</a-upload>
|
||||
<a-modal :open="previewVisible" :footer="null" @cancel="handleCancel">
|
||||
<img alt="example" v-if="fileType === 'img'" style="width: 100%" :src="previewImage" />
|
||||
<video v-if="fileType === 'video'" :src="previewImage" controls autoplay loop muted></video>
|
||||
</a-modal>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script setup>
|
||||
import { ref, watch, onMounted } from 'vue';
|
||||
import { PlusOutlined } from '@ant-design/icons-vue';
|
||||
import { UploadOutlined } from '@ant-design/icons-vue';
|
||||
import { message } from 'ant-design-vue';
|
||||
import { config } from '@/config'
|
||||
import apis from '@/apis'
|
||||
|
||||
defineOptions({
|
||||
name: 'GxUpload',
|
||||
})
|
||||
const fileType = ref('img')
|
||||
const previewVisible = ref(false)
|
||||
const previewImage = ref('')
|
||||
const props = defineProps({
|
||||
modelValue: { type: Array, default: () => [] },
|
||||
headers: { type: Object, default: () => ({}) },
|
||||
multiple: { type: Boolean, default: false },
|
||||
maxSize: { type: Number, default: 10 }, // MB
|
||||
acceptTypes: { type: String, default: '*' },
|
||||
listType: { type: String, default: 'text' },
|
||||
disabled: { type: Boolean, default: false },
|
||||
uploadText: { type: String },
|
||||
fileNumber: { type: Number, default: 6 },
|
||||
width: {
|
||||
type: Number,
|
||||
default: 120,
|
||||
},
|
||||
height: {
|
||||
type: Number,
|
||||
default: 120,
|
||||
},
|
||||
});
|
||||
|
||||
const emit = defineEmits(['update:modelValue', 'uploadSuccess', 'uploadError']);
|
||||
const uploadUrl = config('http.apiBasic') + '/api/v1/upload'
|
||||
const fileList = ref([]);
|
||||
// 初始化文件列表
|
||||
onMounted(() => {
|
||||
console.log(' props.modelValue', props.modelValue)
|
||||
fileList.value = props.modelValue.map(url => ({
|
||||
uid: `preview-${Date.now()}-${Math.random()}`,
|
||||
name: url.substring(url.lastIndexOf('/') + 1),
|
||||
status: 'done',
|
||||
url: url
|
||||
}));
|
||||
});
|
||||
// 文件上传前校验
|
||||
const beforeUpload = (file) => {
|
||||
// const isValidType = props.acceptTypes === '*' ||
|
||||
// props.acceptTypes.split(',').some(type => file.name.endsWith(type.replace('*', '')));
|
||||
// const isValidSize = file.size / 1024 / 1024 < props.maxSize;
|
||||
|
||||
// if (!isValidType) {
|
||||
// message.error(`仅支持 ${props.acceptTypes} 格式文件`);
|
||||
// return false;
|
||||
// }
|
||||
// if (!isValidSize) {
|
||||
// message.error(`文件大小不能超过 ${props.maxSize}MB`);
|
||||
// return false;
|
||||
// }
|
||||
return true;
|
||||
};
|
||||
const handleCancel = () => {
|
||||
previewVisible.value = false;
|
||||
};
|
||||
const getBase64 = (file) => {
|
||||
return new Promise((resolve, reject) => {
|
||||
const reader = new FileReader();
|
||||
reader.readAsDataURL(file);
|
||||
reader.onload = () => resolve(reader.result);
|
||||
reader.onerror = error => reject(error);
|
||||
});
|
||||
}
|
||||
const handlePreview = async (file) => {
|
||||
console.log(file.name)
|
||||
const list = ['.avi', '.mp4', '.mov', '.wmv', '.mkv', '.m4v']
|
||||
const fileSuffix = file.name.substring(file.name.lastIndexOf('.'))
|
||||
if (list.includes(fileSuffix)) {
|
||||
fileType.value = 'video'
|
||||
}
|
||||
if (!file.url && !file.preview) {
|
||||
file.preview = await getBase64(file.originFileObj)
|
||||
}
|
||||
previewImage.value = file.url || file.preview;
|
||||
console.log(previewImage.value)
|
||||
previewVisible.value = true;
|
||||
};
|
||||
|
||||
|
||||
// 修改handleChange方法
|
||||
const handleChange = ({ file, fileList: updatedList }) => {
|
||||
console.log(111)
|
||||
console.log(file.status)
|
||||
console.log(updatedList)
|
||||
// 处理上传成功的情况
|
||||
if (file.status === 'done') {
|
||||
const response = file.response;
|
||||
if (response && response.url) {
|
||||
// 找到当前文件项并更新URL
|
||||
const targetFile = updatedList.find(f => f.uid === file.uid);
|
||||
if (targetFile) {
|
||||
targetFile.url = response.url;
|
||||
message.success(`${file.name} 上传成功`);
|
||||
}
|
||||
|
||||
// 更新外部绑定值
|
||||
const urls = updatedList
|
||||
.filter(item => item.status === 'done')
|
||||
.map(item => item.url);
|
||||
emit('update:modelValue', urls);
|
||||
}
|
||||
} else if (file.status === 'removed') {
|
||||
// 更新外部绑定值
|
||||
const urls = updatedList
|
||||
.filter(item => item.status === 'done')
|
||||
.map(item => item.url);
|
||||
emit('update:modelValue', urls);
|
||||
} else if (file.status === 'error') {
|
||||
message.error(`${file.name} 上传失败`);
|
||||
}
|
||||
};
|
||||
|
||||
// 修复自定义上传方法
|
||||
const handleCustomRequest = async (options) => {
|
||||
const { file, onProgress, onSuccess, onError } = options;
|
||||
|
||||
try {
|
||||
const formData = new FormData();
|
||||
formData.append('file', file);
|
||||
|
||||
const { data } = await apis.common.uploadImg(formData);
|
||||
const fullUrl = config('http.apiBasic') + data;
|
||||
|
||||
// 正确构造文件对象
|
||||
onSuccess({
|
||||
uid: file.uid,
|
||||
name: file.name,
|
||||
status: 'done',
|
||||
url: fullUrl,
|
||||
response: { url: fullUrl } // 确保response包含URL
|
||||
}, file);
|
||||
|
||||
// 触发成功事件
|
||||
emit('uploadSuccess', data);
|
||||
} catch (err) {
|
||||
onError(err);
|
||||
message.error('上传失败');
|
||||
emit('uploadError', err);
|
||||
}
|
||||
};
|
||||
// 同步外部v-model变化
|
||||
watch(() => props.modelValue, (newVal) => {
|
||||
// fileList.value=[...newVal]
|
||||
// 仅同步已完成的项目
|
||||
const doneFiles = fileList.value.filter(f => f.status === 'done');
|
||||
const doneUrls = doneFiles.map(f => f.url);
|
||||
// 避免循环更新
|
||||
if (JSON.stringify(newVal) !== JSON.stringify(doneUrls)) {
|
||||
fileList.value = [
|
||||
...newVal.map(url => {
|
||||
return {
|
||||
uid: `preview-${Date.now()}-${Math.random()}`,
|
||||
name: url.substring(url.lastIndexOf('/') + 1),
|
||||
status: 'done',
|
||||
url: url
|
||||
}
|
||||
}),
|
||||
...fileList.value.filter(f => f.status !== 'done')
|
||||
];
|
||||
}
|
||||
}, { deep: true });
|
||||
</script>
|
||||
<style>
|
||||
/* you can make up upload button and sample style by using stylesheets */
|
||||
.ant-upload-select-picture-card i {
|
||||
font-size: 32px;
|
||||
color: #999;
|
||||
}
|
||||
|
||||
.ant-upload-select-picture-card .ant-upload-text {
|
||||
margin-top: 8px;
|
||||
color: #666;
|
||||
}
|
||||
</style>
|
||||
@ -328,3 +328,9 @@ export const myTrim = (str, char, type = 'right') => {
|
||||
}
|
||||
return str.replace(/^\s+|\s+$/g, '')
|
||||
}
|
||||
/**截取图片路径域名部分 */
|
||||
export const spliceUrl=(fullUrl)=>{
|
||||
if(!fullUrl) return null
|
||||
const pathOnly = fullUrl.replace(/^https?:\/\/[^\/]+/, '');
|
||||
return pathOnly
|
||||
}
|
||||
@ -143,7 +143,7 @@ async function getPageList() {
|
||||
const { code, data } = await apis.common
|
||||
.getPageList({
|
||||
pageSize,
|
||||
page: current,
|
||||
current: current,
|
||||
})
|
||||
.catch(() => {
|
||||
throw new Error()
|
||||
|
||||
@ -115,7 +115,7 @@ async function getPageList() {
|
||||
const { code, data } = await apis.common
|
||||
.getPageList({
|
||||
pageSize,
|
||||
page: current,
|
||||
current: current,
|
||||
})
|
||||
.catch(() => {
|
||||
throw new Error()
|
||||
|
||||
@ -147,7 +147,7 @@ async function getPageList() {
|
||||
const { code, data } = await apis.common
|
||||
.getPageList({
|
||||
pageSize,
|
||||
page: current,
|
||||
current: current,
|
||||
})
|
||||
.catch(() => {
|
||||
throw new Error()
|
||||
|
||||
@ -154,7 +154,7 @@ async function getPageList() {
|
||||
const { code, data } = await apis.common
|
||||
.getPageList({
|
||||
pageSize,
|
||||
page: current,
|
||||
current: current,
|
||||
})
|
||||
.catch(() => {
|
||||
throw new Error()
|
||||
|
||||
@ -131,7 +131,7 @@ async function getPageList() {
|
||||
const { code, data } = await apis.common
|
||||
.getPageList({
|
||||
pageSize,
|
||||
page: current,
|
||||
current: current,
|
||||
})
|
||||
.catch(() => {
|
||||
throw new Error()
|
||||
|
||||
@ -194,7 +194,7 @@ async function getPageList() {
|
||||
const { code, data } = await apis.common
|
||||
.getPageList({
|
||||
pageSize,
|
||||
page: current,
|
||||
current: current,
|
||||
})
|
||||
.catch(() => {
|
||||
throw new Error()
|
||||
|
||||
@ -107,7 +107,7 @@ async function getPageList() {
|
||||
const { code, data } = await apis.common
|
||||
.getPageList({
|
||||
pageSize,
|
||||
page: current,
|
||||
current: current,
|
||||
})
|
||||
.catch(() => {
|
||||
throw new Error()
|
||||
|
||||
@ -162,7 +162,7 @@ async function getPageList() {
|
||||
const { success, data, total } = await apis.system
|
||||
.getLoggers({
|
||||
pageSize,
|
||||
page: current,
|
||||
current: current,
|
||||
...searchFormData.value,
|
||||
startTime: startTime.value,
|
||||
endTime: endTime.value,
|
||||
|
||||
@ -158,7 +158,7 @@ async function getPageList() {
|
||||
const { success, data, total } = await apis.role
|
||||
.getRoleList({
|
||||
pageSize,
|
||||
page: current,
|
||||
current: current,
|
||||
...searchFormData.value,
|
||||
})
|
||||
.catch(() => {
|
||||
|
||||
@ -153,7 +153,7 @@ async function getPageList() {
|
||||
const { success, data, total } = await apis.users
|
||||
.getUsersList({
|
||||
pageSize,
|
||||
page: current,
|
||||
current: current,
|
||||
...searchFormData.value,
|
||||
})
|
||||
.catch(() => {
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user