feat: 添加 PFileUpload 组件及相关类型定义,支持文件上传功能
This commit is contained in:
202
src/__fk-inputs__/components/file-upload/file-upload.vue
Normal file
202
src/__fk-inputs__/components/file-upload/file-upload.vue
Normal 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>
|
Reference in New Issue
Block a user