初始化
This commit is contained in:
@@ -0,0 +1,158 @@
|
||||
<script setup lang="ts">
|
||||
import type { FilesCardProps } from 'vue-element-plus-x/types/FilesCard';
|
||||
|
||||
import { defineExpose, defineProps, nextTick, ref, watch } from 'vue';
|
||||
import { Attachments } from 'vue-element-plus-x';
|
||||
|
||||
import { ElMessage } from 'element-plus';
|
||||
|
||||
import { api } from '#/api/request';
|
||||
|
||||
const props = defineProps({
|
||||
maxSize: {
|
||||
type: Number,
|
||||
default: 2,
|
||||
},
|
||||
action: {
|
||||
type: String,
|
||||
default: '/api/v1/commons/upload',
|
||||
},
|
||||
externalFiles: {
|
||||
type: Array as () => File[],
|
||||
default: () => [],
|
||||
},
|
||||
});
|
||||
|
||||
const emit = defineEmits(['deleteAll']);
|
||||
type SelfFilesCardProps = {
|
||||
fileSize: number;
|
||||
id?: number;
|
||||
name: string;
|
||||
uid: number | string;
|
||||
url: string; // 上传后的文件地址
|
||||
} & FilesCardProps;
|
||||
|
||||
const files = ref<SelfFilesCardProps[]>([]);
|
||||
/**
|
||||
* 上传前校验
|
||||
*/
|
||||
function handleBeforeUpload(file: File) {
|
||||
const maxSizeBytes = props.maxSize * 1024 * 1024;
|
||||
if (file.size > maxSizeBytes) {
|
||||
ElMessage.error(`文件大小不能超过 ${props.maxSize}MB!`);
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* 拖拽上传处理
|
||||
*/
|
||||
async function handleUploadDrop(dropFiles: File[]) {
|
||||
if (dropFiles?.length) {
|
||||
if (dropFiles[0]?.type === '') {
|
||||
ElMessage.error('禁止上传文件夹!');
|
||||
return false;
|
||||
}
|
||||
for (const file of dropFiles) {
|
||||
if (handleBeforeUpload(file)) {
|
||||
await handleHttpRequest({ file });
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 自定义上传请求
|
||||
*/
|
||||
async function handleHttpRequest(options: { file: File }) {
|
||||
const { file } = options;
|
||||
const formData = new FormData();
|
||||
formData.append('file', file);
|
||||
|
||||
try {
|
||||
const res = await api.upload(props.action, { file }, {});
|
||||
|
||||
const fileUrl = res.data.path;
|
||||
const fileItem: SelfFilesCardProps = {
|
||||
id: files.value.length,
|
||||
uid: Date.now() + Math.random(),
|
||||
name: file.name,
|
||||
fileSize: file.size,
|
||||
url: fileUrl,
|
||||
showDelIcon: true,
|
||||
imgVariant: 'square',
|
||||
};
|
||||
|
||||
files.value.push(fileItem);
|
||||
} catch (error) {
|
||||
ElMessage.error(`${file.name} 上传失败`);
|
||||
console.error('上传失败:', error);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 批量上传外部文件(父组件传递的文件数组)
|
||||
*/
|
||||
async function uploadExternalFiles(fileList: File[]) {
|
||||
if (fileList.length === 0) return;
|
||||
|
||||
for (const file of fileList) {
|
||||
if (handleBeforeUpload(file)) {
|
||||
await handleHttpRequest({ file });
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 组件内部完成删除逻辑
|
||||
*/
|
||||
function handleDeleteCard(item: FilesCardProps) {
|
||||
const targetItem = item as SelfFilesCardProps;
|
||||
files.value = files.value.filter((file) => file.id !== targetItem.id);
|
||||
if (files.value.length === 0) {
|
||||
emit('deleteAll');
|
||||
}
|
||||
}
|
||||
/**
|
||||
* 暴露给父组件的核心方法:仅返回URL字符串数组
|
||||
* @returns string[] 纯文件地址列表
|
||||
*/
|
||||
function getFileList(): string[] {
|
||||
return files.value.map((file) => file.url);
|
||||
}
|
||||
|
||||
watch(
|
||||
() => props.externalFiles,
|
||||
async (newFiles) => {
|
||||
if (newFiles.length > 0) {
|
||||
await nextTick();
|
||||
await uploadExternalFiles(newFiles);
|
||||
}
|
||||
},
|
||||
{ deep: true, immediate: true },
|
||||
);
|
||||
|
||||
defineExpose({
|
||||
getFileList,
|
||||
clearFiles() {
|
||||
files.value = [];
|
||||
},
|
||||
});
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<div style="display: flex; flex-direction: column; gap: 12px">
|
||||
<Attachments
|
||||
:http-request="handleHttpRequest"
|
||||
:items="files"
|
||||
drag
|
||||
:before-upload="handleBeforeUpload"
|
||||
:hide-upload="false"
|
||||
@upload-drop="handleUploadDrop"
|
||||
@delete-card="handleDeleteCard"
|
||||
/>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<style scoped lang="less"></style>
|
||||
Reference in New Issue
Block a user