Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

fix(upload): fix the upload status not being updated if the upload was successful #2133

Merged
merged 7 commits into from Jun 28, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
33 changes: 26 additions & 7 deletions packages/core/client/src/schema-component/antd/preview/Preview.tsx
@@ -1,10 +1,9 @@
import { DeleteOutlined, DownloadOutlined, PlusOutlined } from '@ant-design/icons';
import { connect, mapReadPretty } from '@formily/react';
import { Upload as AntdUpload, Button, Progress, Space } from 'antd';
import { Upload as AntdUpload, Button, Progress, Space, UploadFile } from 'antd';
import cls from 'classnames';
import { css } from '@emotion/css';
import { saveAs } from 'file-saver';
import React, { useEffect, useState } from 'react';
import React, { useEffect, useRef, useState } from 'react';
import { useTranslation } from 'react-i18next';
import Lightbox from 'react-image-lightbox';
import 'react-image-lightbox/style.css'; // This only needs to be imported once in your app
Expand Down Expand Up @@ -33,12 +32,15 @@ export const FileSelector = (props: Props) => {
const [photoIndex, setPhotoIndex] = useState(0);
const [visible, setVisible] = useState(false);
const { t } = useTranslation();
const internalFileList = useRef([]);

// 兼容旧版本
const showSelectButton = selectFile === undefined && quickUpload === undefined;

useEffect(() => {
setFileList(toFileList(value));
const fileList = toFileList(value);
setFileList(fileList);
internalFileList.current = fileList;
}, [value]);

const handleRemove = (file) => {
Expand Down Expand Up @@ -70,7 +72,7 @@ export const FileSelector = (props: Props) => {
}
};
return (
<div key={file.id} className={'ant-upload-list-picture-card-container'}>
<div key={file.uid || file.id} className={'ant-upload-list-picture-card-container'}>
<div className="ant-upload-list-item ant-upload-list-item-done ant-upload-list-item-list-type-picture-card">
<div className={'ant-upload-list-item-info'}>
<span className="ant-upload-span">
Expand Down Expand Up @@ -114,6 +116,7 @@ export const FileSelector = (props: Props) => {
icon={<DeleteOutlined />}
onClick={() => {
handleRemove(file);
internalFileList.current = internalFileList.current.filter((item) => item.uid !== file.uid);
}}
/>
)}
Expand Down Expand Up @@ -166,9 +169,14 @@ export const FileSelector = (props: Props) => {
showUploadList={false}
onRemove={handleRemove}
onChange={(info) => {
// info.fileList 有 BUG,会导致上传状态一直是 uploading
// 所以这里仿照 antd 源码,自己维护一个 fileList
const list = updateFileList(info.file, internalFileList.current);
internalFileList.current = list;

// 如果不在这里 setFileList 的话,会导致 onChange 只会执行一次
setFileList([...info.fileList]);
uploadProps.onChange?.(info);
setFileList(toFileList(list));
uploadProps.onChange?.({ fileList: list });
}}
>
<div
Expand Down Expand Up @@ -250,3 +258,14 @@ export const FileSelector = (props: Props) => {
};

export default Preview;

function updateFileList(file: UploadFile, fileList: (UploadFile | Readonly<UploadFile>)[]) {
const nextFileList = [...fileList];
const fileIndex = nextFileList.findIndex(({ uid }) => uid === file.uid);
if (fileIndex === -1) {
nextFileList.push(file);
} else {
nextFileList[fileIndex] = file;
}
return nextFileList;
}
84 changes: 55 additions & 29 deletions packages/core/client/src/schema-component/antd/upload/Upload.tsx
@@ -1,11 +1,10 @@
import { DeleteOutlined, DownloadOutlined, InboxOutlined, LoadingOutlined, PlusOutlined } from '@ant-design/icons';
import { usePrefixCls } from '@formily/antd/esm/__builtins__';
import { connect, mapProps, mapReadPretty } from '@formily/react';
import { Upload as AntdUpload, Button, Progress, Space, Modal } from 'antd';
import { Upload as AntdUpload, Button, Modal, Progress, Space, UploadFile } from 'antd';
import cls from 'classnames';
import { css } from '@emotion/css';
import { saveAs } from 'file-saver';
import React, { useEffect, useState } from 'react';
import React, { useEffect, useRef, useState } from 'react';
import { useTranslation } from 'react-i18next';
import Lightbox from 'react-image-lightbox';
import 'react-image-lightbox/style.css'; // This only needs to be imported once in your app
Expand Down Expand Up @@ -33,12 +32,16 @@ Upload.Attachment = connect((props: UploadProps) => {
const [visible, setVisible] = useState(false);
const [fileType, setFileType] = useState<'image' | 'pdf'>();
const { t } = useTranslation();
const internalFileList = useRef([]);

function closeIFrameModal() {
setVisible(false);
}
useEffect(() => {
if (sync) {
setFileList(toFileList(value));
const fileList = toFileList(value);
setFileList(fileList);
internalFileList.current = fileList;
}
}, [value, sync]);
const uploadProps = useUploadProps({ ...props });
Expand All @@ -55,7 +58,7 @@ Upload.Attachment = connect((props: UploadProps) => {
setFileType('image');
setVisible(true);
setFileIndex(index);
} else if(isPdf(file.extname)) {
} else if (isPdf(file.extname)) {
setVisible(true);
setFileIndex(index);
setFileType('pdf');
Expand All @@ -64,7 +67,7 @@ Upload.Attachment = connect((props: UploadProps) => {
}
};
return (
<div className={'ant-upload-list-picture-card-container'}>
<div key={file.uid || file.id} className={'ant-upload-list-picture-card-container'}>
<div className="ant-upload-list-item ant-upload-list-item-done ant-upload-list-item-list-type-picture-card">
<div className={'ant-upload-list-item-info'}>
<span className="ant-upload-span">
Expand Down Expand Up @@ -115,6 +118,9 @@ Upload.Attachment = connect((props: UploadProps) => {
}
const index = prevFileList.indexOf(file);
prevFileList.splice(index, 1);
internalFileList.current = internalFileList.current.filter(
(item) => item.uid !== file.uid,
);
onChange(toValue([...prevFileList]));
return [...prevFileList];
});
Expand All @@ -141,12 +147,17 @@ Upload.Attachment = connect((props: UploadProps) => {
listType={'picture-card'}
fileList={fileList}
onChange={(info) => {
// info.fileList 有 BUG,会导致上传状态一直是 uploading
// 所以这里仿照 antd 源码,自己维护一个 fileList
const list = updateFileList(info.file, internalFileList.current);
internalFileList.current = list;

setSync(false);
if (multiple) {
if (info.file.status === 'done') {
onChange(toValue(info.fileList));
onChange(toValue(list));
}
setFileList(info.fileList.map(toItem));
setFileList(list.map(toItem));
} else {
if (info.file.status === 'done') {
// TODO(BUG): object 的联动有问题,不响应,折中的办法先置空再赋值
Expand Down Expand Up @@ -198,7 +209,7 @@ Upload.Attachment = connect((props: UploadProps) => {
]}
/>
)}

{visible && fileType === 'pdf' && (
<Modal
open={visible}
Expand All @@ -207,7 +218,7 @@ Upload.Attachment = connect((props: UploadProps) => {
footer={[
<Button
style={{
textTransform: 'capitalize'
textTransform: 'capitalize',
}}
onClick={(e) => {
e.preventDefault();
Expand All @@ -218,31 +229,35 @@ Upload.Attachment = connect((props: UploadProps) => {
>
{t('download')}
</Button>,
<Button onClick={closeIFrameModal} style={{textTransform: 'capitalize'}}>
<Button onClick={closeIFrameModal} style={{ textTransform: 'capitalize' }}>
{t('close')}
</Button>
</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={images[fileIndex].url} style={{
<div
style={{
padding: '8px',
maxWidth: '100%',
maxHeight: 'calc(100vh - 256px)',
height: '90vh',
width: '100%',
maxHeight: '90vh',
flex: '1 1 auto'
}}>
</iframe>
background: 'white',
display: 'flex',
flexDirection: 'column',
alignItems: 'center',
overflowY: 'auto',
}}
>
<iframe
src={images[fileIndex].url}
style={{
width: '100%',
maxHeight: '90vh',
flex: '1 1 auto',
}}
></iframe>
</div>
</Modal>
)}
Expand Down Expand Up @@ -305,3 +320,14 @@ Upload.DraggerV2 = connect(
);

export default Upload;

function updateFileList(file: UploadFile, fileList: (UploadFile | Readonly<UploadFile>)[]) {
const nextFileList = [...fileList];
const fileIndex = nextFileList.findIndex(({ uid }) => uid === file.uid);
if (fileIndex === -1) {
nextFileList.push(file);
} else {
nextFileList[fileIndex] = file;
}
return nextFileList;
}
Expand Up @@ -2,7 +2,6 @@ import { Field } from '@formily/core';
import { useField } from '@formily/react';
import { reaction } from '@formily/reactive';
import { isArr, isValid, toArr as toArray } from '@formily/shared';
import { UploadChangeParam } from 'antd/es/upload';
import { UploadFile } from 'antd/es/upload/interface';
import { useEffect } from 'react';
import { useAPIClient } from '../../../api-client';
Expand Down Expand Up @@ -167,7 +166,7 @@ export const useUploadValidator = (serviceErrorMessage = 'Upload Service Error')

export function useUploadProps<T extends IUploadProps = UploadProps>({ serviceErrorMessage, ...props }: T) {
useUploadValidator(serviceErrorMessage);
const onChange = (param: UploadChangeParam<UploadFile>) => {
const onChange = (param: { fileList: any[] }) => {
props.onChange?.(normalizeFileList([...param.fileList]));
};

Expand Down Expand Up @@ -212,7 +211,10 @@ export function useUploadProps<T extends IUploadProps = UploadProps>({ serviceEr

export const toItem = (file) => {
if (file?.response?.data) {
file = file.response.data;
file = {
uid: file.uid,
...file.response.data,
};
}
return {
...file,
Expand Down
Expand Up @@ -40,7 +40,7 @@
background: rgba(0, 0, 0, 0.5);
}
.ant-upload-list-picture-card-container {
// margin-bottom: 28px;
margin-bottom: 28px;
}
}

Expand Down