mirror of
https://github.com/nocobase/nocobase
synced 2024-11-15 08:26:21 +00:00
refactor(client): add attachment file type registry (#5353)
Some checks are pending
Build Docker Image / build-and-push (push) Waiting to run
Build Pro Image / build-and-push (push) Waiting to run
E2E / Build (push) Waiting to run
E2E / Core and plugins (push) Blocked by required conditions
E2E / plugin-workflow (push) Blocked by required conditions
E2E / plugin-workflow-approval (push) Blocked by required conditions
E2E / plugin-data-source-main (push) Blocked by required conditions
E2E / Comment on PR (push) Blocked by required conditions
NocoBase FrontEnd Test / frontend-test (18) (push) Waiting to run
Some checks are pending
Build Docker Image / build-and-push (push) Waiting to run
Build Pro Image / build-and-push (push) Waiting to run
E2E / Build (push) Waiting to run
E2E / Core and plugins (push) Blocked by required conditions
E2E / plugin-workflow (push) Blocked by required conditions
E2E / plugin-workflow-approval (push) Blocked by required conditions
E2E / plugin-data-source-main (push) Blocked by required conditions
E2E / Comment on PR (push) Blocked by required conditions
NocoBase FrontEnd Test / frontend-test (18) (push) Waiting to run
* refactor(client): add attachment file type registry * refactor(client): change api name of attachmentFileTypes * fix(client): to open file preview in new window if previewer not defined * fix(client): fix attachmentFileTypes default value * refactor(client): simplify file previewer code and allow to preview most file by default * refactor(client): make custom file type has high priority * refactor(client): add types for upload component api * fix(client): fix upload component locale
This commit is contained in:
parent
512df745fa
commit
164847d9a6
@ -800,6 +800,7 @@
|
|||||||
"Try again": "重试一下",
|
"Try again": "重试一下",
|
||||||
"Download logs": "下载日志",
|
"Download logs": "下载日志",
|
||||||
"Download": "下载",
|
"Download": "下载",
|
||||||
|
"File type is not supported for previewing, please download it to preview.": "不支持预览该文件类型,请下载后查看。",
|
||||||
"Click or drag file to this area to upload": "点击或拖拽文件到此区域上传",
|
"Click or drag file to this area to upload": "点击或拖拽文件到此区域上传",
|
||||||
"Support for a single or bulk upload.": "支持单个或批量上传",
|
"Support for a single or bulk upload.": "支持单个或批量上传",
|
||||||
"File size should not exceed {{size}}.": "文件大小不能超过 {{size}}",
|
"File size should not exceed {{size}}.": "文件大小不能超过 {{size}}",
|
||||||
|
@ -10,7 +10,7 @@
|
|||||||
import { DeleteOutlined, DownloadOutlined, InboxOutlined, LoadingOutlined, PlusOutlined } from '@ant-design/icons';
|
import { DeleteOutlined, DownloadOutlined, InboxOutlined, LoadingOutlined, PlusOutlined } from '@ant-design/icons';
|
||||||
import { Field } from '@formily/core';
|
import { Field } from '@formily/core';
|
||||||
import { connect, mapProps, mapReadPretty, useField } from '@formily/react';
|
import { connect, mapProps, mapReadPretty, useField } from '@formily/react';
|
||||||
import { Upload as AntdUpload, Button, Modal, Progress, Space, Tooltip } from 'antd';
|
import { Alert, Upload as AntdUpload, Button, Modal, Progress, Space, Tooltip } from 'antd';
|
||||||
import useUploadStyle from 'antd/es/upload/style';
|
import useUploadStyle from 'antd/es/upload/style';
|
||||||
import cls from 'classnames';
|
import cls from 'classnames';
|
||||||
import { saveAs } from 'file-saver';
|
import { saveAs } from 'file-saver';
|
||||||
@ -18,13 +18,14 @@ import filesize from 'filesize';
|
|||||||
import React, { useCallback, useEffect, useState } from 'react';
|
import React, { useCallback, useEffect, useState } from 'react';
|
||||||
import { useTranslation } from 'react-i18next';
|
import { useTranslation } from 'react-i18next';
|
||||||
import LightBox from 'react-image-lightbox';
|
import LightBox from 'react-image-lightbox';
|
||||||
|
import match from 'mime-match';
|
||||||
import 'react-image-lightbox/style.css'; // This only needs to be imported once in your app
|
import 'react-image-lightbox/style.css'; // This only needs to be imported once in your app
|
||||||
import { withDynamicSchemaProps } from '../../../hoc/withDynamicSchemaProps';
|
import { withDynamicSchemaProps } from '../../../hoc/withDynamicSchemaProps';
|
||||||
import { useProps } from '../../hooks/useProps';
|
import { useProps } from '../../hooks/useProps';
|
||||||
import {
|
import {
|
||||||
FILE_SIZE_LIMIT_DEFAULT,
|
FILE_SIZE_LIMIT_DEFAULT,
|
||||||
isImage,
|
attachmentFileTypes,
|
||||||
isPdf,
|
getThumbnailPlaceholderURL,
|
||||||
normalizeFile,
|
normalizeFile,
|
||||||
toFileList,
|
toFileList,
|
||||||
toValueItem,
|
toValueItem,
|
||||||
@ -34,6 +35,129 @@ import {
|
|||||||
import { useStyles } from './style';
|
import { useStyles } from './style';
|
||||||
import type { ComposedUpload, DraggerProps, DraggerV2Props, UploadProps } from './type';
|
import type { ComposedUpload, DraggerProps, DraggerV2Props, UploadProps } from './type';
|
||||||
|
|
||||||
|
attachmentFileTypes.add({
|
||||||
|
match(file) {
|
||||||
|
return match(file.mimetype || file.type, 'image/*');
|
||||||
|
},
|
||||||
|
getThumbnailURL(file) {
|
||||||
|
return file.url ? `${file.url}${file.thumbnailRule || ''}` : URL.createObjectURL(file.originFileObj);
|
||||||
|
},
|
||||||
|
Previewer({ index, list, onSwitchIndex }) {
|
||||||
|
const onDownload = useCallback(
|
||||||
|
(e) => {
|
||||||
|
e.preventDefault();
|
||||||
|
const file = list[index];
|
||||||
|
saveAs(file.url, `${file.title}${file.extname}`);
|
||||||
|
},
|
||||||
|
[index, list],
|
||||||
|
);
|
||||||
|
return (
|
||||||
|
<LightBox
|
||||||
|
// discourageDownloads={true}
|
||||||
|
mainSrc={list[index]?.url}
|
||||||
|
nextSrc={list[(index + 1) % list.length]?.url}
|
||||||
|
prevSrc={list[(index + list.length - 1) % list.length]?.url}
|
||||||
|
onCloseRequest={() => onSwitchIndex(null)}
|
||||||
|
onMovePrevRequest={() => onSwitchIndex((index + list.length - 1) % list.length)}
|
||||||
|
onMoveNextRequest={() => onSwitchIndex((index + 1) % list.length)}
|
||||||
|
imageTitle={list[index]?.title}
|
||||||
|
toolbarButtons={[
|
||||||
|
<button
|
||||||
|
key={'preview-img'}
|
||||||
|
style={{ fontSize: 22, background: 'none', lineHeight: 1 }}
|
||||||
|
type="button"
|
||||||
|
aria-label="Download"
|
||||||
|
title="Download"
|
||||||
|
className="ril-zoom-in ril__toolbarItemChild ril__builtinButton"
|
||||||
|
onClick={onDownload}
|
||||||
|
>
|
||||||
|
<DownloadOutlined />
|
||||||
|
</button>,
|
||||||
|
]}
|
||||||
|
/>
|
||||||
|
);
|
||||||
|
},
|
||||||
|
});
|
||||||
|
|
||||||
|
const iframePreviewSupportedTypes = ['application/pdf', 'audio/*', 'image/*', 'video/*'];
|
||||||
|
|
||||||
|
function IframePreviewer({ index, list, onSwitchIndex }) {
|
||||||
|
const { t } = useTranslation();
|
||||||
|
const file = list[index];
|
||||||
|
const onOpen = useCallback(
|
||||||
|
(e) => {
|
||||||
|
e.preventDefault();
|
||||||
|
e.stopPropagation();
|
||||||
|
window.open(file.url);
|
||||||
|
},
|
||||||
|
[file],
|
||||||
|
);
|
||||||
|
const onDownload = useCallback(
|
||||||
|
(e) => {
|
||||||
|
e.preventDefault();
|
||||||
|
e.stopPropagation();
|
||||||
|
saveAs(file.url, `${file.title}${file.extname}`);
|
||||||
|
},
|
||||||
|
[file],
|
||||||
|
);
|
||||||
|
const onClose = useCallback(() => {
|
||||||
|
onSwitchIndex(null);
|
||||||
|
}, [onSwitchIndex]);
|
||||||
|
return (
|
||||||
|
<Modal
|
||||||
|
open={index != null}
|
||||||
|
title={file.title}
|
||||||
|
onCancel={onClose}
|
||||||
|
footer={[
|
||||||
|
<Button key="open" onClick={onOpen}>
|
||||||
|
{t('Open in new window')}
|
||||||
|
</Button>,
|
||||||
|
<Button key="download" onClick={onDownload}>
|
||||||
|
{t('Download')}
|
||||||
|
</Button>,
|
||||||
|
<Button key="close" onClick={onClose}>
|
||||||
|
{t('Close')}
|
||||||
|
</Button>,
|
||||||
|
]}
|
||||||
|
width={'85vw'}
|
||||||
|
centered={true}
|
||||||
|
>
|
||||||
|
<div
|
||||||
|
style={{
|
||||||
|
maxWidth: '100%',
|
||||||
|
maxHeight: 'calc(100vh - 256px)',
|
||||||
|
height: '90vh',
|
||||||
|
width: '100%',
|
||||||
|
background: 'white',
|
||||||
|
display: 'flex',
|
||||||
|
flexDirection: 'column',
|
||||||
|
justifyContent: 'center',
|
||||||
|
alignItems: 'center',
|
||||||
|
overflowY: 'auto',
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
{iframePreviewSupportedTypes.some((type) => match(file.mimetype || file.extname, type)) ? (
|
||||||
|
<iframe
|
||||||
|
src={file.url}
|
||||||
|
style={{
|
||||||
|
width: '100%',
|
||||||
|
maxHeight: '90vh',
|
||||||
|
flex: '1 1 auto',
|
||||||
|
border: 'none',
|
||||||
|
}}
|
||||||
|
/>
|
||||||
|
) : (
|
||||||
|
<Alert
|
||||||
|
type="warning"
|
||||||
|
description={t('File type is not supported for previewing, please download it to preview.')}
|
||||||
|
showIcon
|
||||||
|
/>
|
||||||
|
)}
|
||||||
|
</div>
|
||||||
|
</Modal>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
function InternalUpload(props: UploadProps) {
|
function InternalUpload(props: UploadProps) {
|
||||||
const { onChange, ...rest } = props;
|
const { onChange, ...rest } = props;
|
||||||
const onFileChange = useCallback(
|
const onFileChange = useCallback(
|
||||||
@ -85,6 +209,13 @@ function useSizeHint(size: number) {
|
|||||||
return s !== 0 ? t('File size should not exceed {{size}}.', { size: sizeString }) : '';
|
return s !== 0 ? t('File size should not exceed {{size}}.', { size: sizeString }) : '';
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function DefaultThumbnailPreviewer({ file }) {
|
||||||
|
const { componentCls: prefixCls } = useStyles();
|
||||||
|
const { getThumbnailURL = getThumbnailPlaceholderURL } = attachmentFileTypes.getTypeByFile(file) ?? {};
|
||||||
|
const imageUrl = getThumbnailURL(file);
|
||||||
|
return <img src={imageUrl} alt={file.title} className={`${prefixCls}-list-item-image`} />;
|
||||||
|
}
|
||||||
|
|
||||||
function AttachmentListItem(props) {
|
function AttachmentListItem(props) {
|
||||||
const { file, disabled, onPreview, onDelete: propsOnDelete, readPretty } = props;
|
const { file, disabled, onPreview, onDelete: propsOnDelete, readPretty } = props;
|
||||||
const { componentCls: prefixCls } = useStyles();
|
const { componentCls: prefixCls } = useStyles();
|
||||||
@ -104,15 +235,11 @@ function AttachmentListItem(props) {
|
|||||||
saveAs(file.url, `${file.title}${file.extname}`);
|
saveAs(file.url, `${file.title}${file.extname}`);
|
||||||
}, [file]);
|
}, [file]);
|
||||||
|
|
||||||
|
const { ThumbnailPreviewer = DefaultThumbnailPreviewer } = attachmentFileTypes.getTypeByFile(file) ?? {};
|
||||||
|
|
||||||
const item = [
|
const item = [
|
||||||
<span key="thumbnail" className={`${prefixCls}-list-item-thumbnail`}>
|
<span key="thumbnail" className={`${prefixCls}-list-item-thumbnail`}>
|
||||||
{file.imageUrl && (
|
<ThumbnailPreviewer file={file} />
|
||||||
<img
|
|
||||||
src={`${file.imageUrl}${file.thumbnailRule || ''}`}
|
|
||||||
alt={file.title}
|
|
||||||
className={`${prefixCls}-list-item-image`}
|
|
||||||
/>
|
|
||||||
)}
|
|
||||||
</span>,
|
</span>,
|
||||||
<span key="title" className={`${prefixCls}-list-item-name`} title={file.title}>
|
<span key="title" className={`${prefixCls}-list-item-name`} title={file.title}>
|
||||||
{file.status === 'uploading' ? t('Uploading') : file.title}
|
{file.status === 'uploading' ? t('Uploading') : file.title}
|
||||||
@ -166,121 +293,12 @@ function AttachmentListItem(props) {
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
const PreviewerTypes = [
|
|
||||||
{
|
|
||||||
matcher: isImage,
|
|
||||||
Component({ index, list, onSwitchIndex }) {
|
|
||||||
const onDownload = useCallback(
|
|
||||||
(e) => {
|
|
||||||
e.preventDefault();
|
|
||||||
const file = list[index];
|
|
||||||
saveAs(file.url, `${file.title}${file.extname}`);
|
|
||||||
},
|
|
||||||
[index, list],
|
|
||||||
);
|
|
||||||
return (
|
|
||||||
<LightBox
|
|
||||||
// discourageDownloads={true}
|
|
||||||
mainSrc={list[index]?.imageUrl}
|
|
||||||
nextSrc={list[(index + 1) % list.length]?.imageUrl}
|
|
||||||
prevSrc={list[(index + list.length - 1) % list.length]?.imageUrl}
|
|
||||||
onCloseRequest={() => onSwitchIndex(null)}
|
|
||||||
onMovePrevRequest={() => onSwitchIndex((index + list.length - 1) % list.length)}
|
|
||||||
onMoveNextRequest={() => onSwitchIndex((index + 1) % list.length)}
|
|
||||||
imageTitle={list[index]?.title}
|
|
||||||
toolbarButtons={[
|
|
||||||
<button
|
|
||||||
key={'preview-img'}
|
|
||||||
style={{ fontSize: 22, background: 'none', lineHeight: 1 }}
|
|
||||||
type="button"
|
|
||||||
aria-label="Download"
|
|
||||||
title="Download"
|
|
||||||
className="ril-zoom-in ril__toolbarItemChild ril__builtinButton"
|
|
||||||
onClick={onDownload}
|
|
||||||
>
|
|
||||||
<DownloadOutlined />
|
|
||||||
</button>,
|
|
||||||
]}
|
|
||||||
/>
|
|
||||||
);
|
|
||||||
},
|
|
||||||
},
|
|
||||||
{
|
|
||||||
matcher: isPdf,
|
|
||||||
Component({ index, list, onSwitchIndex }) {
|
|
||||||
const { t } = useTranslation();
|
|
||||||
const onDownload = useCallback(
|
|
||||||
(e) => {
|
|
||||||
e.preventDefault();
|
|
||||||
e.stopPropagation();
|
|
||||||
const file = list[index];
|
|
||||||
saveAs(file.url, `${file.title}${file.extname}`);
|
|
||||||
},
|
|
||||||
[index, list],
|
|
||||||
);
|
|
||||||
const onClose = useCallback(() => {
|
|
||||||
onSwitchIndex(null);
|
|
||||||
}, [onSwitchIndex]);
|
|
||||||
return (
|
|
||||||
<Modal
|
|
||||||
open={index != null}
|
|
||||||
title={'PDF - ' + list[index].title}
|
|
||||||
onCancel={onClose}
|
|
||||||
footer={[
|
|
||||||
<Button
|
|
||||||
key="download"
|
|
||||||
style={{
|
|
||||||
textTransform: 'capitalize',
|
|
||||||
}}
|
|
||||||
onClick={onDownload}
|
|
||||||
>
|
|
||||||
{t('Download')}
|
|
||||||
</Button>,
|
|
||||||
<Button key="close" onClick={onClose} style={{ textTransform: 'capitalize' }}>
|
|
||||||
{t('Close')}
|
|
||||||
</Button>,
|
|
||||||
]}
|
|
||||||
width={'85vw'}
|
|
||||||
centered={true}
|
|
||||||
>
|
|
||||||
<div
|
|
||||||
style={{
|
|
||||||
padding: '8px',
|
|
||||||
maxWidth: '100%',
|
|
||||||
maxHeight: 'calc(100vh - 256px)',
|
|
||||||
height: '90vh',
|
|
||||||
width: '100%',
|
|
||||||
background: 'white',
|
|
||||||
display: 'flex',
|
|
||||||
flexDirection: 'column',
|
|
||||||
alignItems: 'center',
|
|
||||||
overflowY: 'auto',
|
|
||||||
}}
|
|
||||||
>
|
|
||||||
<iframe
|
|
||||||
src={list[index].url}
|
|
||||||
style={{
|
|
||||||
width: '100%',
|
|
||||||
maxHeight: '90vh',
|
|
||||||
flex: '1 1 auto',
|
|
||||||
}}
|
|
||||||
/>
|
|
||||||
</div>
|
|
||||||
</Modal>
|
|
||||||
);
|
|
||||||
},
|
|
||||||
},
|
|
||||||
];
|
|
||||||
|
|
||||||
function Previewer({ index, onSwitchIndex, list }) {
|
function Previewer({ index, onSwitchIndex, list }) {
|
||||||
if (index == null) {
|
if (index == null) {
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
const file = list[index];
|
const file = list[index];
|
||||||
const { Component } = PreviewerTypes.find((type) => type.matcher(file)) ?? {};
|
const { Previewer: Component = IframePreviewer } = attachmentFileTypes.getTypeByFile(file) ?? {};
|
||||||
if (!Component) {
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
|
|
||||||
return <Component index={index} list={list} onSwitchIndex={onSwitchIndex} />;
|
return <Component index={index} list={list} onSwitchIndex={onSwitchIndex} />;
|
||||||
}
|
}
|
||||||
@ -298,14 +316,7 @@ export function AttachmentList(props) {
|
|||||||
const onPreview = useCallback(
|
const onPreview = useCallback(
|
||||||
(file) => {
|
(file) => {
|
||||||
const index = fileList.findIndex((item) => item.id === file.id);
|
const index = fileList.findIndex((item) => item.id === file.id);
|
||||||
const previewType = PreviewerTypes.find((type) => type.matcher(file));
|
|
||||||
if (previewType) {
|
|
||||||
setPreview(index);
|
setPreview(index);
|
||||||
} else {
|
|
||||||
if (file.id) {
|
|
||||||
saveAs(file.url, `${file.title}${file.extname}`);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
},
|
},
|
||||||
[fileList],
|
[fileList],
|
||||||
);
|
);
|
||||||
|
@ -8,3 +8,4 @@
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
export * from './Upload';
|
export * from './Upload';
|
||||||
|
export { attachmentFileTypes } from './shared';
|
||||||
|
@ -11,20 +11,52 @@ import { isArr, isValid, toArr as toArray } from '@formily/shared';
|
|||||||
import { UploadFile } from 'antd/es/upload/interface';
|
import { UploadFile } from 'antd/es/upload/interface';
|
||||||
import { useTranslation } from 'react-i18next';
|
import { useTranslation } from 'react-i18next';
|
||||||
import match from 'mime-match';
|
import match from 'mime-match';
|
||||||
import { useCallback } from 'react';
|
import React, { useCallback } from 'react';
|
||||||
import { useAPIClient } from '../../../api-client';
|
import { useAPIClient } from '../../../api-client';
|
||||||
import { UNKNOWN_FILE_ICON, UPLOAD_PLACEHOLDER } from './placeholder';
|
import { UNKNOWN_FILE_ICON, UPLOAD_PLACEHOLDER } from './placeholder';
|
||||||
import type { IUploadProps, UploadProps } from './type';
|
import type { IUploadProps, UploadProps } from './type';
|
||||||
|
|
||||||
export const FILE_SIZE_LIMIT_DEFAULT = 1024 * 1024 * 20;
|
export const FILE_SIZE_LIMIT_DEFAULT = 1024 * 1024 * 20;
|
||||||
|
|
||||||
export const isImage = (file) => {
|
export interface FileModel {
|
||||||
return match(file.mimetype || file.type, 'image/*');
|
id: number;
|
||||||
};
|
filename: string;
|
||||||
|
path: string;
|
||||||
|
title: string;
|
||||||
|
url: string;
|
||||||
|
extname: string;
|
||||||
|
size: number;
|
||||||
|
mimetype: string;
|
||||||
|
}
|
||||||
|
|
||||||
export const isPdf = (file) => {
|
export interface PreviewerProps {
|
||||||
return match(file.mimetype || file.type, 'application/pdf');
|
index: number;
|
||||||
};
|
list: FileModel[];
|
||||||
|
onSwitchIndex(index): void;
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface AttachmentFileType {
|
||||||
|
match(file: any): boolean;
|
||||||
|
getThumbnailURL?(file: any): string;
|
||||||
|
ThumbnailPreviewer?: React.ComponentType<{ file: FileModel }>;
|
||||||
|
Previewer?: React.ComponentType<PreviewerProps>;
|
||||||
|
}
|
||||||
|
|
||||||
|
export class AttachmentFileTypes {
|
||||||
|
types: AttachmentFileType[] = [];
|
||||||
|
add(type: AttachmentFileType) {
|
||||||
|
// NOTE: use unshift to make sure the custom type has higher priority
|
||||||
|
this.types.unshift(type);
|
||||||
|
}
|
||||||
|
getTypeByFile(file): Omit<AttachmentFileType, 'match'> {
|
||||||
|
return this.types.find((type) => type.match(file));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @experimental
|
||||||
|
*/
|
||||||
|
export const attachmentFileTypes = new AttachmentFileTypes();
|
||||||
|
|
||||||
const toArr = (value) => {
|
const toArr = (value) => {
|
||||||
if (!isValid(value)) {
|
if (!isValid(value)) {
|
||||||
@ -36,7 +68,7 @@ const toArr = (value) => {
|
|||||||
return toArray(value);
|
return toArray(value);
|
||||||
};
|
};
|
||||||
|
|
||||||
export const testOpts = (ext: RegExp, options: { exclude?: string[]; include?: string[] }) => {
|
const testOpts = (ext: RegExp, options: { exclude?: string[]; include?: string[] }) => {
|
||||||
if (options && isArr(options.include)) {
|
if (options && isArr(options.include)) {
|
||||||
return options.include.some((url) => ext.test(url));
|
return options.include.some((url) => ext.test(url));
|
||||||
}
|
}
|
||||||
@ -48,26 +80,19 @@ export const testOpts = (ext: RegExp, options: { exclude?: string[]; include?: s
|
|||||||
return true;
|
return true;
|
||||||
};
|
};
|
||||||
|
|
||||||
export const getImageByUrl = (url: string, options: any = {}) => {
|
export function getThumbnailPlaceholderURL(file, options: any = {}) {
|
||||||
for (let i = 0; i < UPLOAD_PLACEHOLDER.length; i++) {
|
for (let i = 0; i < UPLOAD_PLACEHOLDER.length; i++) {
|
||||||
// console.log(UPLOAD_PLACEHOLDER[i].ext, testOpts(UPLOAD_PLACEHOLDER[i].ext, options));
|
// console.log(UPLOAD_PLACEHOLDER[i].ext, testOpts(UPLOAD_PLACEHOLDER[i].ext, options));
|
||||||
if (UPLOAD_PLACEHOLDER[i].ext.test(url)) {
|
if (UPLOAD_PLACEHOLDER[i].ext.test(file.extname || file.filename || file.url || file.name)) {
|
||||||
if (testOpts(UPLOAD_PLACEHOLDER[i].ext, options)) {
|
if (testOpts(UPLOAD_PLACEHOLDER[i].ext, options)) {
|
||||||
return UPLOAD_PLACEHOLDER[i].icon || UNKNOWN_FILE_ICON;
|
return UPLOAD_PLACEHOLDER[i].icon || UNKNOWN_FILE_ICON;
|
||||||
} else {
|
} else {
|
||||||
return url;
|
return file.name;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return UNKNOWN_FILE_ICON;
|
return UNKNOWN_FILE_ICON;
|
||||||
};
|
}
|
||||||
|
|
||||||
export const getURL = (target: any) => {
|
|
||||||
return target?.['url'] || target?.['downloadURL'] || target?.['imgURL'] || target?.['name'];
|
|
||||||
};
|
|
||||||
export const getThumbURL = (target: any) => {
|
|
||||||
return target?.['thumbUrl'] || target?.['url'] || target?.['downloadURL'] || target?.['imgURL'] || target?.['name'];
|
|
||||||
};
|
|
||||||
|
|
||||||
export function getResponseMessage({ error, response }: UploadFile<any>) {
|
export function getResponseMessage({ error, response }: UploadFile<any>) {
|
||||||
if (error instanceof Error && 'isAxiosError' in error) {
|
if (error instanceof Error && 'isAxiosError' in error) {
|
||||||
@ -93,24 +118,14 @@ export function getResponseMessage({ error, response }: UploadFile<any>) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
export function normalizeFile(file: UploadFile & Record<string, any>) {
|
export function normalizeFile(file: UploadFile & Record<string, any>) {
|
||||||
const imageUrl = isImage(file) ? URL.createObjectURL(file.originFileObj) : getImageByUrl(file.name);
|
|
||||||
const response = getResponseMessage(file);
|
const response = getResponseMessage(file);
|
||||||
return {
|
return {
|
||||||
...file,
|
...file,
|
||||||
title: file.name,
|
title: file.name,
|
||||||
thumbUrl: imageUrl,
|
|
||||||
imageUrl,
|
|
||||||
response,
|
response,
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
export const normalizeFileList = (fileList: UploadFile[]) => {
|
|
||||||
if (fileList && fileList.length) {
|
|
||||||
return fileList.map(normalizeFile);
|
|
||||||
}
|
|
||||||
return [];
|
|
||||||
};
|
|
||||||
|
|
||||||
export function useUploadProps<T extends IUploadProps = UploadProps>(props: T) {
|
export function useUploadProps<T extends IUploadProps = UploadProps>(props: T) {
|
||||||
const api = useAPIClient();
|
const api = useAPIClient();
|
||||||
|
|
||||||
@ -166,11 +181,6 @@ export const toItem = (file) => {
|
|||||||
...file,
|
...file,
|
||||||
id: file.id || file.uid,
|
id: file.id || file.uid,
|
||||||
title: file.title || file.name,
|
title: file.title || file.name,
|
||||||
imageUrl: isImage(file)
|
|
||||||
? file.url
|
|
||||||
: getImageByUrl(file.url, {
|
|
||||||
exclude: ['.png', '.jpg', '.jpeg', '.gif', '.svg', '.webp', '.bmp', '.ico'],
|
|
||||||
}),
|
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -178,12 +188,6 @@ export const toFileList = (fileList: any) => {
|
|||||||
return toArr(fileList).filter(Boolean).map(toItem);
|
return toArr(fileList).filter(Boolean).map(toItem);
|
||||||
};
|
};
|
||||||
|
|
||||||
export const toValue = (fileList: any) => {
|
|
||||||
return toArr(fileList)
|
|
||||||
.filter((file) => !file.response || file.status === 'done')
|
|
||||||
.map((file) => file?.response?.data || file);
|
|
||||||
};
|
|
||||||
|
|
||||||
const Rules: Record<string, RuleFunction> = {
|
const Rules: Record<string, RuleFunction> = {
|
||||||
size(file, options: number): null | string {
|
size(file, options: number): null | string {
|
||||||
const size = options ?? FILE_SIZE_LIMIT_DEFAULT;
|
const size = options ?? FILE_SIZE_LIMIT_DEFAULT;
|
||||||
|
Loading…
Reference in New Issue
Block a user