refactor: upload types, close #5047

This commit is contained in:
tangjinzhou 2021-12-17 15:32:32 +08:00
parent 06516ec60d
commit 9784b429f5
16 changed files with 92 additions and 212 deletions

View File

@ -214,7 +214,7 @@ export {
TypographyTitle,
} from './typography';
export type { UploadProps } from './upload';
export type { UploadProps, UploadListProps, UploadChangeParam } from './upload';
export { default as Upload, UploadDragger } from './upload';

View File

@ -1,12 +1,12 @@
import { defineComponent } from 'vue';
import { getOptionProps, getSlot } from '../_util/props-util';
import Upload from './Upload';
import { UploadProps } from './interface';
import { uploadProps } from './interface';
export default defineComponent({
name: 'AUploadDragger',
inheritAttrs: false,
props: UploadProps,
props: uploadProps,
render() {
const props = getOptionProps(this);
const { height, ...restProps } = props;

View File

@ -10,39 +10,19 @@ import defaultLocale from '../locale-provider/default';
import { defaultConfigProvider } from '../config-provider';
import Dragger from './Dragger';
import UploadList from './UploadList';
import { UploadProps } from './interface';
import type { UploadFile } from './interface';
import { uploadProps } from './interface';
import { T, fileToObject, genPercentAdd, getFileItem, removeFileItem } from './utils';
import { defineComponent, inject } from 'vue';
import { getDataAndAriaProps } from '../_util/util';
import { useInjectFormItemContext } from '../form/FormItemContext';
export type UploadFileStatus = 'error' | 'success' | 'done' | 'uploading' | 'removed';
export interface UploadFile<T = any> {
uid: string;
size?: number;
name: string;
fileName?: string;
lastModified?: number;
lastModifiedDate?: Date;
url?: string;
status?: UploadFileStatus;
percent?: number;
thumbUrl?: string;
originFileObj?: any;
response?: T;
error?: any;
linkProps?: any;
type?: string;
xhr?: T;
preview?: string;
}
export default defineComponent({
name: 'AUpload',
mixins: [BaseMixin],
inheritAttrs: false,
Dragger,
props: initDefaultProps(UploadProps, {
props: initDefaultProps(uploadProps, {
type: 'select',
multiple: false,
action: '',

View File

@ -20,12 +20,12 @@ import EyeOutlined from '@ant-design/icons-vue/EyeOutlined';
import Tooltip from '../tooltip';
import Progress from '../progress';
import classNames from '../_util/classNames';
import { UploadListProps } from './interface';
import { uploadListProps } from './interface';
export default defineComponent({
name: 'AUploadList',
mixins: [BaseMixin],
props: initDefaultProps(UploadListProps, {
props: initDefaultProps(uploadListProps, {
listType: 'text', // or picture
progressAttr: {
strokeWidth: 2,

View File

@ -2,10 +2,10 @@ import { mount } from '@vue/test-utils';
import Upload from '..';
import { T, fileToObject, genPercentAdd, getFileItem, removeFileItem } from '../utils';
import PropsTypes from '../../_util/vue-types';
import { UploadListProps } from '../interface';
import { uploadListProps } from '../interface';
import { setup, teardown } from './mock';
UploadListProps.items = PropsTypes.any;
uploadListProps.items = PropsTypes.any;
describe('Upload', () => {
beforeEach(() => setup());

View File

@ -3,11 +3,11 @@ import * as Vue from 'vue';
import Upload from '..';
import { errorRequest, successRequest } from './requests';
import PropsTypes from '../../_util/vue-types';
import { UploadListProps } from '../interface';
import { uploadListProps } from '../interface';
import { sleep } from '../../../tests/utils';
import { h } from 'vue';
UploadListProps.items = PropsTypes.any;
uploadListProps.items = PropsTypes.any;
const delay = timeout => new Promise(resolve => setTimeout(resolve, timeout));
const fileList = [

View File

@ -42,22 +42,7 @@ Click to upload user's avatar, and validate size and format of picture with `bef
import { PlusOutlined, LoadingOutlined } from '@ant-design/icons-vue';
import { message } from 'ant-design-vue';
import { defineComponent, ref } from 'vue';
interface FileItem {
uid: string;
name?: string;
status?: string;
response?: string;
url?: string;
type?: string;
size: number;
originFileObj: any;
}
interface FileInfo {
file: FileItem;
fileList: FileItem[];
}
import type { UploadChangeParam, UploadProps } from 'ant-design-vue';
function getBase64(img: Blob, callback: (base64Url: string) => void) {
const reader = new FileReader();
@ -74,7 +59,7 @@ export default defineComponent({
const loading = ref<boolean>(false);
const imageUrl = ref<string>('');
const handleChange = (info: FileInfo) => {
const handleChange = (info: UploadChangeParam) => {
if (info.file.status === 'uploading') {
loading.value = true;
return;
@ -92,7 +77,7 @@ export default defineComponent({
}
};
const beforeUpload = (file: FileItem) => {
const beforeUpload = (file: UploadProps['fileList'][number]) => {
const isJpgOrPng = file.type === 'image/jpeg' || file.type === 'image/png';
if (!isJpgOrPng) {
message.error('You can only upload JPG file!');

View File

@ -34,26 +34,14 @@ Classic mode. File selection dialog pops up when upload button is clicked.
import { message } from 'ant-design-vue';
import { UploadOutlined } from '@ant-design/icons-vue';
import { defineComponent, ref } from 'vue';
interface FileItem {
uid: string;
name?: string;
status?: string;
response?: string;
url?: string;
}
interface FileInfo {
file: FileItem;
fileList: FileItem[];
}
import type { UploadChangeParam } from 'ant-design-vue';
export default defineComponent({
components: {
UploadOutlined,
},
setup() {
const handleChange = (info: FileInfo) => {
const handleChange = (info: UploadChangeParam) => {
if (info.file.status !== 'uploading') {
console.log(info.file, info.fileList);
}

View File

@ -26,25 +26,14 @@ Use `defaultFileList` for uploaded files when page init.
<script lang="ts">
import { UploadOutlined } from '@ant-design/icons-vue';
import { defineComponent, ref } from 'vue';
interface FileItem {
uid: string;
name?: string;
status?: string;
response?: string;
url?: string;
}
interface FileInfo {
file: FileItem;
fileList: FileItem[];
}
import type { UploadChangeParam, UploadProps } from 'ant-design-vue';
export default defineComponent({
components: {
UploadOutlined,
},
setup() {
const fileList = ref<FileItem[]>([
const fileList = ref<UploadProps['fileList']>([
{
uid: '1',
name: 'xxx.png',
@ -67,7 +56,7 @@ export default defineComponent({
},
]);
const handleChange = ({ file, fileList }: FileInfo) => {
const handleChange = ({ file, fileList }: UploadChangeParam) => {
if (file.status !== 'uploading') {
console.log(file, fileList);
}

View File

@ -41,26 +41,14 @@ We can upload serveral files at once in modern browsers by giving the input the
import { InboxOutlined } from '@ant-design/icons-vue';
import { message } from 'ant-design-vue';
import { defineComponent, ref } from 'vue';
interface FileItem {
uid: string;
name?: string;
status?: string;
response?: string;
url?: string;
}
interface FileInfo {
file: FileItem;
fileList: FileItem[];
}
import type { UploadChangeParam } from 'ant-design-vue';
export default defineComponent({
components: {
InboxOutlined,
},
setup() {
const handleChange = (info: FileInfo) => {
const handleChange = (info: UploadChangeParam) => {
const status = info.file.status;
if (status !== 'uploading') {
console.log(info.file, info.fileList);

View File

@ -39,26 +39,14 @@ You can gain full control over filelist by configuring `fileList`. You can accom
<script lang="ts">
import { UploadOutlined } from '@ant-design/icons-vue';
import { defineComponent, ref } from 'vue';
interface FileItem {
uid: string;
name?: string;
status?: string;
response?: Response;
url: string;
}
interface FileInfo {
file: FileItem;
fileList: FileItem[];
}
import type { UploadChangeParam, UploadProps } from 'ant-design-vue';
export default defineComponent({
components: {
UploadOutlined,
},
setup() {
const fileList = ref<FileItem[]>([
const fileList = ref<UploadProps['fileList']>([
{
uid: '-1',
name: 'xxx.png',
@ -66,7 +54,7 @@ export default defineComponent({
url: 'http://www.baidu.com/xxx.png',
},
]);
const handleChange = (info: FileInfo) => {
const handleChange = (info: UploadChangeParam) => {
let resFileList = [...info.fileList];
// 1. Limit the number of uploaded files

View File

@ -36,6 +36,7 @@ After users upload picture, the thumbnail will be shown in list. The upload butt
<script lang="ts">
import { PlusOutlined } from '@ant-design/icons-vue';
import { defineComponent, ref } from 'vue';
import type { UploadChangeParam, UploadProps } from 'ant-design-vue';
function getBase64(file: File) {
return new Promise((resolve, reject) => {
@ -46,22 +47,6 @@ function getBase64(file: File) {
});
}
interface FileItem {
uid: string;
name?: string;
status?: string;
response?: string;
percent?: number;
url?: string;
preview?: string;
originFileObj?: any;
}
interface FileInfo {
file: FileItem;
fileList: FileItem[];
}
export default defineComponent({
components: {
PlusOutlined,
@ -70,7 +55,7 @@ export default defineComponent({
const previewVisible = ref<boolean>(false);
const previewImage = ref<string | undefined>('');
const fileList = ref<FileItem[]>([
const fileList = ref<UploadProps['fileList']>([
{
uid: '-1',
name: 'image.png',
@ -105,14 +90,14 @@ export default defineComponent({
const handleCancel = () => {
previewVisible.value = false;
};
const handlePreview = async (file: FileItem) => {
const handlePreview = async (file: UploadProps['fileList'][number]) => {
if (!file.url && !file.preview) {
file.preview = (await getBase64(file.originFileObj)) as string;
}
previewImage.value = file.url || file.preview;
previewVisible.value = true;
};
const handleChange = ({ fileList: newFileList }: FileInfo) => {
const handleChange = ({ fileList: newFileList }: UploadChangeParam) => {
fileList.value = newFileList;
};

View File

@ -46,22 +46,14 @@ If uploaded file is a picture, the thumbnail can be shown. `IE8/9` do not suppor
<script lang="ts">
import { UploadOutlined } from '@ant-design/icons-vue';
import { defineComponent, ref } from 'vue';
interface FileItem {
uid: string;
name?: string;
status?: string;
response?: string;
url?: string;
thumbUrl?: string;
}
import type { UploadProps } from 'ant-design-vue';
export default defineComponent({
components: {
UploadOutlined,
},
setup() {
const fileList = ref<FileItem[]>([
const fileList = ref<UploadProps['fileList']>([
{
uid: '-1',
name: 'xxx.png',
@ -77,7 +69,7 @@ export default defineComponent({
thumbUrl: 'https://zos.alipayobjects.com/rmsportal/jkjgkEfvpUPVyRjUImniVslZfWPnJuuZ.png',
},
]);
const fileList1 = ref<FileItem[]>([
const fileList1 = ref<UploadProps['fileList']>([
{
uid: '-1',
name: 'xxx.png',

View File

@ -39,41 +39,31 @@ import request from 'umi-request';
import { UploadOutlined } from '@ant-design/icons-vue';
import { message } from 'ant-design-vue';
import { defineComponent, ref } from 'vue';
interface FileItem {
uid: string;
name?: string;
status?: string;
response?: string;
url?: string;
preview?: string;
originFileObj?: any;
file: string | Blob;
}
import type { UploadProps } from 'ant-design-vue';
export default defineComponent({
components: {
UploadOutlined,
},
setup() {
const fileList = ref<FileItem[]>([]);
const fileList = ref<UploadProps['fileList']>([]);
const uploading = ref<boolean>(false);
const handleRemove = (file: FileItem) => {
const handleRemove: UploadProps['onRemove'] = file => {
const index = fileList.value.indexOf(file);
const newFileList = fileList.value.slice();
newFileList.splice(index, 1);
fileList.value = newFileList;
};
const beforeUpload = (file: FileItem) => {
const beforeUpload: UploadProps['beforeUpload'] = file => {
fileList.value = [...fileList.value, file];
return false;
};
const handleUpload = () => {
const formData = new FormData();
fileList.value.forEach((file: FileItem) => {
fileList.value.forEach((file: UploadProps['fileList'][number]) => {
formData.append('files[]', file as any);
});
uploading.value = true;

View File

@ -2,7 +2,7 @@ import type { App, Plugin } from 'vue';
import Upload from './Upload';
import Dragger from './Dragger';
export { UploadProps, UploadListProps, UploadChangeParam } from './interface';
export type { UploadProps, UploadListProps, UploadChangeParam } from './interface';
Upload.Dragger = Dragger;

View File

@ -1,3 +1,4 @@
import type { ExtractPropTypes, PropType } from 'vue';
import { tuple } from '../_util/type';
import PropsTypes from '../_util/vue-types';
@ -15,58 +16,51 @@ export interface VcFile extends File {
readonly webkitRelativePath: string;
}
// export const UploadFile = PropsTypes.shape({
// uid: PropsTypes.oneOfType([
// PropsTypes.string,
// PropsTypes.number,
// ]),
// size: PropsTypes.number,
// name: PropsTypes.string,
// filename: PropsTypes.string,
// lastModified: PropsTypes.number,
// lastModifiedDate: PropsTypes.any,
// url: PropsTypes.string,
// status: UploadFileStatus,
// percent: PropsTypes.number,
// thumbUrl: PropsTypes.string,
// originFileObj: PropsTypes.any,
// response: PropsTypes.any,
// error: PropsTypes.any,
// linkProps: PropsTypes.any,
// type: PropsTypes.string,
// }).loose
function UploadFile({ uid, name }) {
if (!uid && uid !== 0) return false;
if (!['string', 'number'].includes(typeof uid)) return false;
if (name === '' || typeof name !== 'string') return false;
return true;
export type UploadFileStatus = 'error' | 'success' | 'done' | 'uploading' | 'removed';
export interface UploadFile<T = any> {
uid: string;
size?: number;
name: string;
fileName?: string;
lastModified?: number;
lastModifiedDate?: Date;
url?: string;
status?: UploadFileStatus;
percent?: number;
thumbUrl?: string;
originFileObj?: any;
response?: T;
error?: any;
linkProps?: any;
type?: string;
xhr?: T;
preview?: string;
}
export const UploadChangeParam = {
file: PropsTypes.custom(UploadFile),
fileList: PropsTypes.arrayOf(PropsTypes.custom(UploadFile)),
event: PropsTypes.object,
};
export interface UploadChangeParam<T extends object = UploadFile> {
file: T;
fileList: UploadFile[];
event?: { percent: number };
}
export const ShowUploadListInterface = PropsTypes.shape({
showRemoveIcon: PropsTypes.looseBool,
showPreviewIcon: PropsTypes.looseBool,
}).loose;
export const UploadLocale = PropsTypes.shape({
uploading: PropsTypes.string,
removeFile: PropsTypes.string,
downloadFile: PropsTypes.string,
uploadError: PropsTypes.string,
previewFile: PropsTypes.string,
}).loose;
export interface UploadLocale {
uploading?: string;
removeFile?: string;
downloadFile?: string;
uploadError?: string;
previewFile?: string;
}
export const UploadProps = {
export const uploadProps = {
type: PropsTypes.oneOf(tuple('drag', 'select')),
name: PropsTypes.string,
defaultFileList: PropsTypes.arrayOf(PropsTypes.custom(UploadFile)),
fileList: PropsTypes.arrayOf(PropsTypes.custom(UploadFile)),
defaultFileList: { type: Array as PropType<UploadFile[]> },
fileList: { type: Array as PropType<UploadFile[]> },
action: PropsTypes.oneOfType([PropsTypes.string, PropsTypes.func]),
directory: PropsTypes.looseBool,
data: PropsTypes.oneOfType([PropsTypes.object, PropsTypes.func]),
@ -86,36 +80,37 @@ export const UploadProps = {
customRequest: PropsTypes.func,
withCredentials: PropsTypes.looseBool,
openFileDialogOnClick: PropsTypes.looseBool,
locale: UploadLocale,
locale: { type: Object as PropType<UploadLocale> },
height: PropsTypes.number,
id: PropsTypes.string,
previewFile: PropsTypes.func,
transformFile: PropsTypes.func,
onChange: PropsTypes.func,
onPreview: PropsTypes.func,
onRemove: PropsTypes.func,
onDownload: PropsTypes.func,
'onUpdate:fileList': PropsTypes.func,
onChange: { type: Function as PropType<(info: UploadChangeParam) => void> },
onPreview: { type: Function as PropType<(file: UploadFile) => void> },
onRemove: {
type: Function as PropType<(file: UploadFile) => void | boolean | Promise<void | boolean>>,
},
onDownload: { type: Function as PropType<(file: UploadFile) => void> },
'onUpdate:fileList': { type: Function as PropType<(files: UploadFile[]) => void> },
};
export const UploadState = {
fileList: PropsTypes.arrayOf(PropsTypes.custom(UploadFile)),
dragState: PropsTypes.string,
};
export const UploadListProps = {
export type UploadProps = Partial<ExtractPropTypes<typeof uploadProps>>;
export const uploadListProps = {
listType: PropsTypes.oneOf(tuple('text', 'picture', 'picture-card')),
// items: PropsTypes.arrayOf(UploadFile),
items: PropsTypes.arrayOf(PropsTypes.custom(UploadFile)),
// items: PropsTypes.any,
items: { type: Array as PropType<UploadFile[]> },
progressAttr: PropsTypes.object,
prefixCls: PropsTypes.string,
showRemoveIcon: PropsTypes.looseBool,
showDownloadIcon: PropsTypes.looseBool,
showPreviewIcon: PropsTypes.looseBool,
locale: UploadLocale,
locale: { type: Object as PropType<UploadLocale> },
previewFile: PropsTypes.func,
onPreview: PropsTypes.func,
onRemove: PropsTypes.func,
onDownload: PropsTypes.func,
onPreview: { type: Function as PropType<(file: UploadFile) => void> },
onRemove: {
type: Function as PropType<(file: UploadFile) => void | boolean>,
},
onDownload: { type: Function as PropType<(file: UploadFile) => void> },
};
export type UploadListProps = Partial<ExtractPropTypes<typeof uploadListProps>>;