diff --git a/packages/core/client/src/locale/zh-CN.json b/packages/core/client/src/locale/zh-CN.json index b5f16d5eca..e1921008d9 100644 --- a/packages/core/client/src/locale/zh-CN.json +++ b/packages/core/client/src/locale/zh-CN.json @@ -800,6 +800,7 @@ "Try again": "重试一下", "Download logs": "下载日志", "Download": "下载", + "File type is not supported for previewing, please download it to preview.": "不支持预览该文件类型,请下载后查看。", "Click or drag file to this area to upload": "点击或拖拽文件到此区域上传", "Support for a single or bulk upload.": "支持单个或批量上传", "File size should not exceed {{size}}.": "文件大小不能超过 {{size}}", diff --git a/packages/core/client/src/schema-component/antd/upload/Upload.tsx b/packages/core/client/src/schema-component/antd/upload/Upload.tsx index c6ab7ad48f..1877693a06 100644 --- a/packages/core/client/src/schema-component/antd/upload/Upload.tsx +++ b/packages/core/client/src/schema-component/antd/upload/Upload.tsx @@ -10,7 +10,7 @@ import { DeleteOutlined, DownloadOutlined, InboxOutlined, LoadingOutlined, PlusOutlined } from '@ant-design/icons'; import { Field } from '@formily/core'; 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 cls from 'classnames'; import { saveAs } from 'file-saver'; @@ -18,13 +18,14 @@ import filesize from 'filesize'; import React, { useCallback, useEffect, useState } from 'react'; import { useTranslation } from 'react-i18next'; 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 { withDynamicSchemaProps } from '../../../hoc/withDynamicSchemaProps'; import { useProps } from '../../hooks/useProps'; import { FILE_SIZE_LIMIT_DEFAULT, - isImage, - isPdf, + attachmentFileTypes, + getThumbnailPlaceholderURL, normalizeFile, toFileList, toValueItem, @@ -34,6 +35,129 @@ import { import { useStyles } from './style'; 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 ( + onSwitchIndex(null)} + onMovePrevRequest={() => onSwitchIndex((index + list.length - 1) % list.length)} + onMoveNextRequest={() => onSwitchIndex((index + 1) % list.length)} + imageTitle={list[index]?.title} + toolbarButtons={[ + , + ]} + /> + ); + }, +}); + +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 ( + + {t('Open in new window')} + , + , + , + ]} + width={'85vw'} + centered={true} + > +
+ {iframePreviewSupportedTypes.some((type) => match(file.mimetype || file.extname, type)) ? ( +