feat: 添加 PFileUpload 组件及相关类型定义,支持文件上传功能
All checks were successful
/ test (push) Successful in 3s
/ surge (push) Successful in 55s

This commit is contained in:
严浩
2024-12-31 15:23:51 +08:00
parent ab39617e7b
commit 6a1a7d2d47
9 changed files with 669 additions and 457 deletions

View File

@ -0,0 +1,202 @@
<script setup lang="ts">
import type { FormKitFrameworkContext } from '@formkit/core';
import FileUpload, { type FileUploadUploaderEvent } from 'primevue/fileupload';
import { computed, onMounted, useTemplateRef } from 'vue';
import FileUploadItem from './file-upload-item.vue';
import type { CustomRequest, FileExt, FileUploadInst, PropFilesToValue, PropValueToFiles } from './types';
const props = defineProps<{
context: FormKitFrameworkContext & {
fileLimit?: number;
maxFileSize?: number;
customRequest?: CustomRequest;
valueToFiles?: PropValueToFiles;
filesToValue?: PropFilesToValue;
autoUpload?: boolean;
};
}>();
const formkitContext = props.context;
const customRequest = props.context.customRequest;
const fileUploadRef = useTemplateRef<FileUploadInst>('fileUploadRef');
const cmpt_disabled = computed(() => {
if (fileUploadRef.value) {
// 有上传失败的文件
if (fileUploadRef.value.uploadedFiles.some((f) => f.status === 'failed')) {
return true;
}
// 已上传文件数量超过限制(这里是大于*等于*
if (fileUploadRef.value.uploadedFileCount >= (formkitContext.fileLimit ?? Infinity)) {
return true;
}
// 已上传和待上传文件数量超过限制(这里是*大于*
const uploaded_and_pending_count = fileUploadRef.value.uploadedFileCount + fileUploadRef.value.files.length;
if (uploaded_and_pending_count > (formkitContext.fileLimit ?? Infinity)) {
return true;
}
}
return false;
});
const cmpt_showUploadButton = computed(() => {
if (fileUploadRef.value?.files?.length) {
return true;
}
return false;
});
const changeModelValue = () => {
const uploadedFiles = fileUploadRef.value!.uploadedFiles.filter((f) => f.status === 'uploaded');
if (!formkitContext.filesToValue) {
console.warn('[FileUpload] filesToValue is not defined');
return;
}
formkitContext.node.input(formkitContext.filesToValue(uploadedFiles));
};
const changeUploadedFiles = () => {
if (!formkitContext.valueToFiles) {
console.warn('[FileUpload] valueToFiles is not defined');
return;
}
try {
const files = formkitContext.valueToFiles(formkitContext._value);
fileUploadRef.value!.uploadedFiles = files.map((f) => ({
name: f.name,
url: f.url,
status: f.status || 'uploaded',
progress: f.progress || 100,
}));
fileUploadRef.value!.uploadedFileCount = files.length;
} catch (error) {
console.warn('[FileUpload] valueToFiles error:', error);
}
};
onMounted(() => {
changeUploadedFiles();
});
const onUploader = (event: FileUploadUploaderEvent) => {
if (!customRequest) {
console.warn('[FileUpload] customRequest is not defined');
return;
}
const files = event.files as FileExt[];
for (const file of files) {
fileUploadRef.value!.uploadedFiles.push({
rawFile: file,
name: file.name,
url: '',
status: 'uploading',
progress: 0,
});
const fileItem = fileUploadRef.value!.uploadedFiles[fileUploadRef.value!.uploadedFiles.length - 1];
customRequest({
file,
onProgress: (percent) => {
fileItem.progress = percent;
},
})
.then((result) => {
fileItem.status = 'uploaded';
fileItem.url = result.url;
changeModelValue();
})
.catch(() => {
fileItem.status = 'failed';
});
}
};
</script>
<template>
<FileUpload
ref="fileUploadRef"
:auto="formkitContext.autoUpload"
:disabled="cmpt_disabled"
:showUploadButton="cmpt_showUploadButton"
:showCancelButton="false"
:customUpload="true"
mode="advanced"
:multiple="true"
accept="image/*"
:maxFileSize="formkitContext.maxFileSize"
invalidFileSizeMessage="文件 {0} 大小超过限制 {1}"
:fileLimit="formkitContext.fileLimit"
invalidFileLimitMessage="最多只能上传 {0} 个文件,请移除多余文件后点击上传"
@uploader="onUploader"
:chooseButtonProps="{ size: 'small' }"
:uploadButtonProps="{ size: 'small', severity: 'secondary' }"
:cancelButtonProps="{ size: 'small', severity: 'secondary' }"
>
<template #empty>
<Message
size="small"
severity="info"
>请上传图片</Message
>
</template>
<template #content="{ messages, removeFileCallback, removeUploadedFileCallback }">
<Message
size="small"
v-for="msg of messages"
closable
@close="fileUploadRef!.messages = []"
:key="msg"
severity="error"
>{{ msg }}</Message
>
<!-- 已上传列表上传中上传成功上传失败 -->
<template
v-for="(file, index) of fileUploadRef?.uploadedFiles"
:key="file.name + file.url"
>
<FileUploadItem
:url="file.url || file.rawFile?.objectURL || ''"
:filename="file.name || file.url || '未知文件'"
@remove="
() => {
fileUploadRef!.uploadedFileCount--;
removeUploadedFileCallback(index);
}
"
:status="file.status"
:progress="file.progress"
/>
</template>
<!-- 待上传列表 -->
<template
v-for="(file, index) of fileUploadRef?.files"
:key="file.name + file.type + file.size"
>
<FileUploadItem
:url="file.objectURL"
:filename="file.name"
@remove="removeFileCallback(index)"
status="pending"
/>
</template>
</template>
</FileUpload>
</template>
<style>
.p-floatlabel:has(.p-fileupload) label {
top: var(--p-floatlabel-over-active-top);
transform: translateY(0);
font-size: var(--p-floatlabel-active-font-size);
font-weight: var(--p-floatlabel-label-active-font-weight);
}
.p-fileupload-content .p-progressbar {
--p-fileupload-progressbar-height: 1rem;
}
</style>