improve upload component
This commit is contained in:
parent
15105c1efb
commit
a635c955c6
@ -23,6 +23,7 @@
|
|||||||
"@types/react-dom": "^17.0.0"
|
"@types/react-dom": "^17.0.0"
|
||||||
},
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
|
"@types/file-saver": "^2.0.3",
|
||||||
"@types/jest": "^24.0.18",
|
"@types/jest": "^24.0.18",
|
||||||
"@types/koa": "^2.13.1",
|
"@types/koa": "^2.13.1",
|
||||||
"@types/lodash": "^4.14.169",
|
"@types/lodash": "^4.14.169",
|
||||||
|
@ -29,6 +29,7 @@
|
|||||||
"axios": "^0.21.1",
|
"axios": "^0.21.1",
|
||||||
"beautiful-react-hooks": "^0.35.0",
|
"beautiful-react-hooks": "^0.35.0",
|
||||||
"constate": "^3.3.0",
|
"constate": "^3.3.0",
|
||||||
|
"file-saver": "^2.0.5",
|
||||||
"flat": "^5.0.2",
|
"flat": "^5.0.2",
|
||||||
"html-react-parser": "^1.2.7",
|
"html-react-parser": "^1.2.7",
|
||||||
"lodash": "^4.17.21",
|
"lodash": "^4.17.21",
|
||||||
|
@ -5,10 +5,13 @@ const schema = {
|
|||||||
type: 'object',
|
type: 'object',
|
||||||
properties: {
|
properties: {
|
||||||
input: {
|
input: {
|
||||||
type: 'object',
|
type: 'string',
|
||||||
title: `编辑模式`,
|
title: `编辑模式`,
|
||||||
'x-decorator': 'FormItem',
|
'x-decorator': 'FormItem',
|
||||||
'x-component': 'Upload.File',
|
'x-component': 'Upload.Attachment',
|
||||||
|
'x-component-props': {
|
||||||
|
// multiple: true,
|
||||||
|
},
|
||||||
'x-reactions': {
|
'x-reactions': {
|
||||||
target: 'read',
|
target: 'read',
|
||||||
fulfill: {
|
fulfill: {
|
||||||
@ -19,11 +22,14 @@ const schema = {
|
|||||||
},
|
},
|
||||||
},
|
},
|
||||||
read: {
|
read: {
|
||||||
type: 'object',
|
type: 'string',
|
||||||
title: `阅读模式`,
|
title: `阅读模式`,
|
||||||
'x-read-pretty': true,
|
'x-read-pretty': true,
|
||||||
'x-decorator': 'FormItem',
|
'x-decorator': 'FormItem',
|
||||||
'x-component': 'Upload.File',
|
'x-component': 'Upload.Attachment',
|
||||||
|
'x-component-props': {
|
||||||
|
// multiple: true,
|
||||||
|
},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
|
@ -7,30 +7,72 @@ const schema = {
|
|||||||
input: {
|
input: {
|
||||||
type: 'object',
|
type: 'object',
|
||||||
title: `编辑模式`,
|
title: `编辑模式`,
|
||||||
|
default: [
|
||||||
|
{
|
||||||
|
id: 45,
|
||||||
|
title: 's33766399',
|
||||||
|
name: 's33766399',
|
||||||
|
filename: 'cd48dc833ab01aa3959ac39309fc39de.jpg',
|
||||||
|
extname: '.jpg',
|
||||||
|
size: null,
|
||||||
|
mimetype: 'image/jpeg',
|
||||||
|
path: '',
|
||||||
|
meta: {},
|
||||||
|
status: 'uploading',
|
||||||
|
percent: 60,
|
||||||
|
url: 'https://nocobase.oss-cn-beijing.aliyuncs.com/cd48dc833ab01aa3959ac39309fc39de.jpg',
|
||||||
|
created_at: '2021-08-13T15:00:17.423Z',
|
||||||
|
updated_at: '2021-08-13T15:00:17.423Z',
|
||||||
|
created_by_id: null,
|
||||||
|
updated_by_id: null,
|
||||||
|
storage_id: 2,
|
||||||
|
},
|
||||||
|
],
|
||||||
'x-decorator': 'FormItem',
|
'x-decorator': 'FormItem',
|
||||||
'x-component': 'Upload.File',
|
'x-component': 'Upload.Attachment',
|
||||||
'x-component-props': {
|
'x-component-props': {
|
||||||
multiple: true,
|
multiple: true,
|
||||||
},
|
},
|
||||||
'x-reactions': {
|
'x-reactions': [
|
||||||
target: 'read',
|
{
|
||||||
fulfill: {
|
target: 'read',
|
||||||
state: {
|
fulfill: {
|
||||||
value: '{{$self.value}}',
|
state: {
|
||||||
|
value: '{{$self.value}}',
|
||||||
|
},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
},
|
{
|
||||||
|
target: 'read2',
|
||||||
|
fulfill: {
|
||||||
|
state: {
|
||||||
|
value: '{{$self.value}}',
|
||||||
|
},
|
||||||
|
},
|
||||||
|
}
|
||||||
|
],
|
||||||
},
|
},
|
||||||
read: {
|
read: {
|
||||||
type: 'object',
|
type: 'object',
|
||||||
title: `阅读模式`,
|
title: `阅读模式`,
|
||||||
'x-read-pretty': true,
|
'x-read-pretty': true,
|
||||||
'x-decorator': 'FormItem',
|
'x-decorator': 'FormItem',
|
||||||
'x-component': 'Upload.File',
|
'x-component': 'Upload.Attachment',
|
||||||
'x-component-props': {
|
'x-component-props': {
|
||||||
multiple: true,
|
multiple: true,
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
read2: {
|
||||||
|
type: 'object',
|
||||||
|
title: `小图预览`,
|
||||||
|
'x-read-pretty': true,
|
||||||
|
'x-decorator': 'FormItem',
|
||||||
|
'x-component': 'Upload.Attachment',
|
||||||
|
'x-component-props': {
|
||||||
|
multiple: true,
|
||||||
|
size: 'small',
|
||||||
|
},
|
||||||
|
},
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -6,7 +6,7 @@ import {
|
|||||||
observer,
|
observer,
|
||||||
useField,
|
useField,
|
||||||
} from '@formily/react';
|
} from '@formily/react';
|
||||||
import { Button, Progress, Upload as AntdUpload } from 'antd';
|
import { Button, Progress, Space, Upload as AntdUpload } from 'antd';
|
||||||
import {
|
import {
|
||||||
UploadChangeParam,
|
UploadChangeParam,
|
||||||
UploadProps as AntdUploadProps,
|
UploadProps as AntdUploadProps,
|
||||||
@ -14,7 +14,7 @@ import {
|
|||||||
} from 'antd/lib/upload';
|
} from 'antd/lib/upload';
|
||||||
import { reaction } from '@formily/reactive';
|
import { reaction } from '@formily/reactive';
|
||||||
import { UploadFile } from 'antd/lib/upload/interface';
|
import { UploadFile } from 'antd/lib/upload/interface';
|
||||||
import { isArr, toArr } from '@formily/shared';
|
import { isArr, toArr as toArray, isValid } from '@formily/shared';
|
||||||
import { UPLOAD_PLACEHOLDER } from './placeholder';
|
import { UPLOAD_PLACEHOLDER } from './placeholder';
|
||||||
import { usePrefixCls } from '@formily/antd/esm/__builtins__';
|
import { usePrefixCls } from '@formily/antd/esm/__builtins__';
|
||||||
import { useState } from 'react';
|
import { useState } from 'react';
|
||||||
@ -23,10 +23,26 @@ import 'react-image-lightbox/style.css'; // This only needs to be imported once
|
|||||||
import { useMap } from 'ahooks';
|
import { useMap } from 'ahooks';
|
||||||
import DeleteOutlined from '@ant-design/icons/DeleteOutlined';
|
import DeleteOutlined from '@ant-design/icons/DeleteOutlined';
|
||||||
import UploadOutlined from '@ant-design/icons/UploadOutlined';
|
import UploadOutlined from '@ant-design/icons/UploadOutlined';
|
||||||
|
import PlusOutlined from '@ant-design/icons/PlusOutlined';
|
||||||
|
import DownloadOutlined from '@ant-design/icons/DownloadOutlined';
|
||||||
|
import './style.less';
|
||||||
|
import cls from 'classnames';
|
||||||
|
import { saveAs } from 'file-saver';
|
||||||
|
|
||||||
|
const toArr = (value) => {
|
||||||
|
if (!isValid(value)) {
|
||||||
|
return [];
|
||||||
|
}
|
||||||
|
if (Object.keys(value).length === 0) {
|
||||||
|
return [];
|
||||||
|
}
|
||||||
|
return toArray(value);
|
||||||
|
};
|
||||||
|
|
||||||
type UploadProps = Omit<AntdUploadProps, 'onChange'> & {
|
type UploadProps = Omit<AntdUploadProps, 'onChange'> & {
|
||||||
onChange?: (fileList: UploadFile[]) => void;
|
onChange?: (fileList: UploadFile[]) => void;
|
||||||
serviceErrorMessage?: string;
|
serviceErrorMessage?: string;
|
||||||
|
value?: any;
|
||||||
};
|
};
|
||||||
|
|
||||||
type DraggerProps = Omit<AntdDraggerProps, 'onChange'> & {
|
type DraggerProps = Omit<AntdDraggerProps, 'onChange'> & {
|
||||||
@ -37,6 +53,7 @@ type DraggerProps = Omit<AntdDraggerProps, 'onChange'> & {
|
|||||||
type ComposedUpload = React.FC<UploadProps> & {
|
type ComposedUpload = React.FC<UploadProps> & {
|
||||||
Dragger?: React.FC<DraggerProps>;
|
Dragger?: React.FC<DraggerProps>;
|
||||||
File?: React.FC<UploadProps>;
|
File?: React.FC<UploadProps>;
|
||||||
|
Attachment?: React.FC<UploadProps>;
|
||||||
};
|
};
|
||||||
|
|
||||||
type IUploadProps = {
|
type IUploadProps = {
|
||||||
@ -221,6 +238,16 @@ function toItem(file) {
|
|||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function toFileList(fileList: any) {
|
||||||
|
return toArr(fileList).map(toItem);
|
||||||
|
}
|
||||||
|
|
||||||
|
function toValue(fileList: any) {
|
||||||
|
return toArr(fileList)
|
||||||
|
.filter((file) => !file.response || file.status === 'done')
|
||||||
|
.map((file) => file?.response?.data || file);
|
||||||
|
}
|
||||||
|
|
||||||
function toMap(fileList: any) {
|
function toMap(fileList: any) {
|
||||||
if (!fileList) {
|
if (!fileList) {
|
||||||
return [];
|
return [];
|
||||||
@ -228,13 +255,14 @@ function toMap(fileList: any) {
|
|||||||
if (typeof fileList !== 'object') {
|
if (typeof fileList !== 'object') {
|
||||||
return [];
|
return [];
|
||||||
}
|
}
|
||||||
if (Object.keys(fileList).length === 0) {
|
|
||||||
return [];
|
|
||||||
}
|
|
||||||
let list = fileList;
|
let list = fileList;
|
||||||
if (!Array.isArray(fileList) && typeof fileList === 'object') {
|
if (!Array.isArray(fileList)) {
|
||||||
|
if (Object.keys({ ...fileList }).length === 0) {
|
||||||
|
return [];
|
||||||
|
}
|
||||||
list = [fileList];
|
list = [fileList];
|
||||||
}
|
}
|
||||||
|
console.log({ list, fileList });
|
||||||
return list.map((item) => {
|
return list.map((item) => {
|
||||||
return [item.id || item.uid, toItem(item)];
|
return [item.id || item.uid, toItem(item)];
|
||||||
});
|
});
|
||||||
@ -281,7 +309,7 @@ Upload.File = connect(
|
|||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
setAll(toMap(value));
|
setAll(toMap(value));
|
||||||
}, [value]);
|
}, [value]);
|
||||||
console.log('value', value);
|
console.log('mapmapmapmapmap', map);
|
||||||
return (
|
return (
|
||||||
<div>
|
<div>
|
||||||
<AntdUpload
|
<AntdUpload
|
||||||
@ -289,10 +317,11 @@ Upload.File = connect(
|
|||||||
{...useUploadProps({ ...others, multiple })}
|
{...useUploadProps({ ...others, multiple })}
|
||||||
onChange={({ file }) => {
|
onChange={({ file }) => {
|
||||||
console.log({ multiple, file });
|
console.log({ multiple, file });
|
||||||
|
const f = toItem(file);
|
||||||
if (multiple) {
|
if (multiple) {
|
||||||
set(file.uid, toItem(file));
|
set(f.id, f);
|
||||||
} else {
|
} else {
|
||||||
setAll([[file.uid, toItem(file)]]);
|
setAll([[f.id, f]]);
|
||||||
}
|
}
|
||||||
if (file.status === 'done') {
|
if (file.status === 'done') {
|
||||||
if (multiple) {
|
if (multiple) {
|
||||||
@ -432,4 +461,294 @@ Upload.File = connect(
|
|||||||
|
|
||||||
Upload.Dragger = Dragger;
|
Upload.Dragger = Dragger;
|
||||||
|
|
||||||
|
Upload.Attachment = connect(
|
||||||
|
(props: UploadProps) => {
|
||||||
|
const { disabled, multiple, value, onChange } = props;
|
||||||
|
const [fileList, setFileList] = useState([]);
|
||||||
|
const [sync, setSync] = useState(true);
|
||||||
|
const images = fileList;
|
||||||
|
const [photoIndex, setPhotoIndex] = useState(0);
|
||||||
|
const [visible, setVisible] = useState(false);
|
||||||
|
useEffect(() => {
|
||||||
|
if (sync) {
|
||||||
|
setFileList(toFileList(value));
|
||||||
|
}
|
||||||
|
}, [value, sync]);
|
||||||
|
return (
|
||||||
|
<div>
|
||||||
|
<div className={cls('ant-upload-picture-card-wrapper nb-upload')}>
|
||||||
|
<div className={'ant-upload-list ant-upload-list-picture-card'}>
|
||||||
|
{fileList.map((file) => {
|
||||||
|
const handleClick = (e) => {
|
||||||
|
e.preventDefault();
|
||||||
|
const index = fileList.indexOf(file);
|
||||||
|
setVisible(true);
|
||||||
|
setPhotoIndex(index);
|
||||||
|
};
|
||||||
|
return (
|
||||||
|
<div 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">
|
||||||
|
<a
|
||||||
|
className="ant-upload-list-item-thumbnail"
|
||||||
|
href={file.url}
|
||||||
|
target="_blank"
|
||||||
|
rel="noopener noreferrer"
|
||||||
|
onClick={handleClick}
|
||||||
|
>
|
||||||
|
{file.imageUrl && (
|
||||||
|
<img
|
||||||
|
src={file.imageUrl}
|
||||||
|
alt={file.title}
|
||||||
|
className="ant-upload-list-item-image"
|
||||||
|
/>
|
||||||
|
)}
|
||||||
|
</a>
|
||||||
|
<a
|
||||||
|
target="_blank"
|
||||||
|
rel="noopener noreferrer"
|
||||||
|
className="ant-upload-list-item-name"
|
||||||
|
title={file.title}
|
||||||
|
href={file.url}
|
||||||
|
onClick={handleClick}
|
||||||
|
>
|
||||||
|
{file.status === 'uploading'
|
||||||
|
? '上传中...'
|
||||||
|
: file.title}
|
||||||
|
</a>
|
||||||
|
</span>
|
||||||
|
</div>
|
||||||
|
<span className={'ant-upload-list-item-actions'}>
|
||||||
|
<Space size={3}>
|
||||||
|
<Button
|
||||||
|
size={'small'}
|
||||||
|
type={'text'}
|
||||||
|
icon={<DownloadOutlined />}
|
||||||
|
onClick={() => {
|
||||||
|
saveAs(file.url, `${file.title}${file.extname}`);
|
||||||
|
}}
|
||||||
|
/>
|
||||||
|
{!disabled && (
|
||||||
|
<Button
|
||||||
|
size={'small'}
|
||||||
|
type={'text'}
|
||||||
|
icon={<DeleteOutlined />}
|
||||||
|
onClick={() => {
|
||||||
|
setSync(false);
|
||||||
|
setFileList((prevFileList) => {
|
||||||
|
if (!multiple) {
|
||||||
|
onChange(null);
|
||||||
|
return [];
|
||||||
|
}
|
||||||
|
const index = prevFileList.indexOf(file);
|
||||||
|
prevFileList.splice(index, 1);
|
||||||
|
onChange(toValue([...prevFileList]));
|
||||||
|
return [...prevFileList];
|
||||||
|
});
|
||||||
|
}}
|
||||||
|
/>
|
||||||
|
)}
|
||||||
|
</Space>
|
||||||
|
</span>
|
||||||
|
{file.status === 'uploading' && (
|
||||||
|
<div className={'ant-upload-list-item-progress'}>
|
||||||
|
<Progress
|
||||||
|
strokeWidth={2}
|
||||||
|
type={'line'}
|
||||||
|
showInfo={false}
|
||||||
|
percent={file.percent}
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
)}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
})}
|
||||||
|
<div className={'ant-upload-list-picture-card-container'}>
|
||||||
|
<AntdUpload
|
||||||
|
{...useUploadProps({ ...props })}
|
||||||
|
disabled={disabled}
|
||||||
|
multiple={multiple}
|
||||||
|
listType={'picture-card'}
|
||||||
|
fileList={fileList}
|
||||||
|
action={`${process.env.API_URL}attachments:upload`}
|
||||||
|
onChange={(info) => {
|
||||||
|
setSync(false);
|
||||||
|
if (multiple) {
|
||||||
|
if (info.file.status === 'done') {
|
||||||
|
onChange(toValue(info.fileList));
|
||||||
|
}
|
||||||
|
setFileList(info.fileList.map(toItem));
|
||||||
|
} else {
|
||||||
|
if (info.file.status === 'done') {
|
||||||
|
console.log('field.value', info.file?.response?.data);
|
||||||
|
// TODO(BUG): object 的联动有问题,不响应,折中的办法先置空再赋值
|
||||||
|
onChange(null);
|
||||||
|
onChange(info.file?.response?.data);
|
||||||
|
}
|
||||||
|
setFileList([toItem(info.file)]);
|
||||||
|
}
|
||||||
|
}}
|
||||||
|
showUploadList={false}
|
||||||
|
>
|
||||||
|
{!disabled && (multiple || toArr(value).length < 1) && (
|
||||||
|
<span>
|
||||||
|
<PlusOutlined />
|
||||||
|
<br /> 上传
|
||||||
|
</span>
|
||||||
|
)}
|
||||||
|
</AntdUpload>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
{visible && (
|
||||||
|
<Lightbox
|
||||||
|
// discourageDownloads={true}
|
||||||
|
mainSrc={images[photoIndex]?.imageUrl}
|
||||||
|
nextSrc={images[(photoIndex + 1) % images.length]?.imageUrl}
|
||||||
|
prevSrc={
|
||||||
|
images[(photoIndex + images.length - 1) % images.length]?.imageUrl
|
||||||
|
}
|
||||||
|
onCloseRequest={() => setVisible(false)}
|
||||||
|
onMovePrevRequest={() =>
|
||||||
|
setPhotoIndex((photoIndex + images.length - 1) % images.length)
|
||||||
|
}
|
||||||
|
onMoveNextRequest={() =>
|
||||||
|
setPhotoIndex((photoIndex + 1) % images.length)
|
||||||
|
}
|
||||||
|
imageTitle={images[photoIndex]?.title}
|
||||||
|
toolbarButtons={[
|
||||||
|
<button
|
||||||
|
style={{ fontSize: 22, background: 'none', lineHeight: 1 }}
|
||||||
|
type="button"
|
||||||
|
aria-label="Zoom in"
|
||||||
|
title="Zoom in"
|
||||||
|
className="ril-zoom-in ril__toolbarItemChild ril__builtinButton"
|
||||||
|
onClick={() => {
|
||||||
|
const file = images[photoIndex];
|
||||||
|
saveAs(file.url, `${file.title}${file.extname}`);
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
<DownloadOutlined />
|
||||||
|
</button>,
|
||||||
|
]}
|
||||||
|
/>
|
||||||
|
)}
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
},
|
||||||
|
mapReadPretty((props) => {
|
||||||
|
const field = useField<Formily.Core.Models.Field>();
|
||||||
|
const images = toImages(toArr(field.value));
|
||||||
|
const [photoIndex, setPhotoIndex] = useState(0);
|
||||||
|
const [visible, setVisible] = useState(false);
|
||||||
|
const { size } = props;
|
||||||
|
console.log('field.value', field.value, images);
|
||||||
|
return (
|
||||||
|
<div>
|
||||||
|
<div
|
||||||
|
className={cls(
|
||||||
|
'ant-upload-picture-card-wrapper nb-upload',
|
||||||
|
size ? `nb-upload-${size}` : null,
|
||||||
|
)}
|
||||||
|
>
|
||||||
|
<div className={'ant-upload-list ant-upload-list-picture-card'}>
|
||||||
|
{images.map((file) => {
|
||||||
|
const handleClick = (e) => {
|
||||||
|
e.preventDefault();
|
||||||
|
const index = images.indexOf(file);
|
||||||
|
setVisible(true);
|
||||||
|
setPhotoIndex(index);
|
||||||
|
};
|
||||||
|
return (
|
||||||
|
<div 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">
|
||||||
|
<a
|
||||||
|
className="ant-upload-list-item-thumbnail"
|
||||||
|
href={file.url}
|
||||||
|
target="_blank"
|
||||||
|
rel="noopener noreferrer"
|
||||||
|
onClick={handleClick}
|
||||||
|
>
|
||||||
|
{file.imageUrl && (
|
||||||
|
<img
|
||||||
|
src={file.imageUrl}
|
||||||
|
alt={file.title}
|
||||||
|
className="ant-upload-list-item-image"
|
||||||
|
/>
|
||||||
|
)}
|
||||||
|
</a>
|
||||||
|
<a
|
||||||
|
target="_blank"
|
||||||
|
rel="noopener noreferrer"
|
||||||
|
className="ant-upload-list-item-name"
|
||||||
|
title={file.title}
|
||||||
|
href={file.url}
|
||||||
|
onClick={handleClick}
|
||||||
|
>
|
||||||
|
{file.title}
|
||||||
|
</a>
|
||||||
|
</span>
|
||||||
|
</div>
|
||||||
|
{size !== 'small' && (
|
||||||
|
<span className={'ant-upload-list-item-actions'}>
|
||||||
|
<Space size={3}>
|
||||||
|
<Button
|
||||||
|
size={'small'}
|
||||||
|
type={'text'}
|
||||||
|
icon={<DownloadOutlined />}
|
||||||
|
onClick={async () => {
|
||||||
|
saveAs(file.url, `${file.title}${file.extname}`);
|
||||||
|
}}
|
||||||
|
/>
|
||||||
|
</Space>
|
||||||
|
</span>
|
||||||
|
)}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
})}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
{visible && (
|
||||||
|
<Lightbox
|
||||||
|
// discourageDownloads={true}
|
||||||
|
mainSrc={images[photoIndex]?.imageUrl}
|
||||||
|
nextSrc={images[(photoIndex + 1) % images.length]?.imageUrl}
|
||||||
|
prevSrc={
|
||||||
|
images[(photoIndex + images.length - 1) % images.length]?.imageUrl
|
||||||
|
}
|
||||||
|
onCloseRequest={() => setVisible(false)}
|
||||||
|
onMovePrevRequest={() =>
|
||||||
|
setPhotoIndex((photoIndex + images.length - 1) % images.length)
|
||||||
|
}
|
||||||
|
onMoveNextRequest={() =>
|
||||||
|
setPhotoIndex((photoIndex + 1) % images.length)
|
||||||
|
}
|
||||||
|
imageTitle={images[photoIndex]?.title}
|
||||||
|
toolbarButtons={[
|
||||||
|
<button
|
||||||
|
style={{ fontSize: 22, background: 'none', lineHeight: 1 }}
|
||||||
|
type="button"
|
||||||
|
aria-label="Zoom in"
|
||||||
|
title="Zoom in"
|
||||||
|
className="ril-zoom-in ril__toolbarItemChild ril__builtinButton"
|
||||||
|
onClick={() => {
|
||||||
|
const file = images[photoIndex];
|
||||||
|
saveAs(file.url, `${file.title}${file.extname}`);
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
<DownloadOutlined />
|
||||||
|
</button>,
|
||||||
|
]}
|
||||||
|
/>
|
||||||
|
)}
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
}),
|
||||||
|
);
|
||||||
|
|
||||||
export default Upload;
|
export default Upload;
|
||||||
|
53
packages/client/src/schemas/upload/style.less
Normal file
53
packages/client/src/schemas/upload/style.less
Normal file
@ -0,0 +1,53 @@
|
|||||||
|
.nb-file-list {
|
||||||
|
display: flex;
|
||||||
|
}
|
||||||
|
.nb-file-item {
|
||||||
|
}
|
||||||
|
|
||||||
|
.nb-upload {
|
||||||
|
.ant-upload-list-item-actions {
|
||||||
|
left: auto;
|
||||||
|
right: 4px;
|
||||||
|
top: 4px;
|
||||||
|
transform: none;
|
||||||
|
}
|
||||||
|
.ant-upload-list-picture-card .ant-upload-list-item-info {
|
||||||
|
overflow: inherit;
|
||||||
|
}
|
||||||
|
.ant-upload-list-picture-card .ant-upload-list-item-name {
|
||||||
|
display: block;
|
||||||
|
margin-top: 10px;
|
||||||
|
font-size: 13px;
|
||||||
|
color: #636363;
|
||||||
|
}
|
||||||
|
.ant-upload-list-picture-card .ant-upload-list-item:hover .ant-upload-list-item-info::before {
|
||||||
|
display: none;
|
||||||
|
}
|
||||||
|
.ant-upload-list-picture-card .ant-upload-list-item-progress {
|
||||||
|
bottom: calc(50% - 11px);
|
||||||
|
pointer-events: none;
|
||||||
|
}
|
||||||
|
.ant-btn {
|
||||||
|
background: rgba(0,0,0,.5);
|
||||||
|
// .anticon {
|
||||||
|
// color: #1890ff;
|
||||||
|
// }
|
||||||
|
}
|
||||||
|
.ant-upload-list-picture-card-container {
|
||||||
|
margin-bottom: 28px;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.nb-upload-small {
|
||||||
|
.ant-upload-list-picture-card-container {
|
||||||
|
margin: 0 3px 3px 0;
|
||||||
|
height: 32px;
|
||||||
|
width: 32px;
|
||||||
|
}
|
||||||
|
.ant-upload-list-picture-card .ant-upload-list-item-name {
|
||||||
|
display: none;
|
||||||
|
}
|
||||||
|
.ant-upload-list-picture .ant-upload-list-item, .ant-upload-list-picture-card .ant-upload-list-item {
|
||||||
|
padding: 1px;
|
||||||
|
}
|
||||||
|
}
|
10
yarn.lock
10
yarn.lock
@ -3610,6 +3610,11 @@
|
|||||||
"@types/qs" "*"
|
"@types/qs" "*"
|
||||||
"@types/serve-static" "*"
|
"@types/serve-static" "*"
|
||||||
|
|
||||||
|
"@types/file-saver@^2.0.3":
|
||||||
|
version "2.0.3"
|
||||||
|
resolved "https://registry.npmjs.org/@types/file-saver/-/file-saver-2.0.3.tgz#b734c4f5a04d20615eaed3dc106e2ab321082009"
|
||||||
|
integrity sha512-MBIou8pd/41jkff7s97B47bc9+p0BszqqDJsO51yDm49uUxeKzrfuNl5fSLC6BpLEWKA8zlwyqALVmXrFwoBHQ==
|
||||||
|
|
||||||
"@types/glob@^7.1.1":
|
"@types/glob@^7.1.1":
|
||||||
version "7.1.3"
|
version "7.1.3"
|
||||||
resolved "https://registry.npmjs.org/@types/glob/-/glob-7.1.3.tgz#e6ba80f36b7daad2c685acd9266382e68985c183"
|
resolved "https://registry.npmjs.org/@types/glob/-/glob-7.1.3.tgz#e6ba80f36b7daad2c685acd9266382e68985c183"
|
||||||
@ -8719,6 +8724,11 @@ file-entry-cache@^6.0.1:
|
|||||||
dependencies:
|
dependencies:
|
||||||
flat-cache "^3.0.4"
|
flat-cache "^3.0.4"
|
||||||
|
|
||||||
|
file-saver@^2.0.5:
|
||||||
|
version "2.0.5"
|
||||||
|
resolved "https://registry.npmjs.org/file-saver/-/file-saver-2.0.5.tgz#d61cfe2ce059f414d899e9dd6d4107ee25670c38"
|
||||||
|
integrity sha512-P9bmyZ3h/PRG+Nzga+rbdI4OEpNDzAVyy74uVO9ATgzLK6VtAsYybF/+TOCvrc0MO793d6+42lLyZTw7/ArVzA==
|
||||||
|
|
||||||
file-uri-to-path@1.0.0:
|
file-uri-to-path@1.0.0:
|
||||||
version "1.0.0"
|
version "1.0.0"
|
||||||
resolved "https://registry.npmjs.org/file-uri-to-path/-/file-uri-to-path-1.0.0.tgz#553a7b8446ff6f684359c445f1e37a05dacc33dd"
|
resolved "https://registry.npmjs.org/file-uri-to-path/-/file-uri-to-path-1.0.0.tgz#553a7b8446ff6f684359c445f1e37a05dacc33dd"
|
||||||
|
Loading…
Reference in New Issue
Block a user