|
@@ -1,23 +1,30 @@
|
|
|
-import { FC, ReactNode } from 'react';
|
|
|
-import { UploadFile } from 'antd/es/upload/interface';
|
|
|
-import { DeleteOutlined, DownloadOutlined, EyeOutlined } from '@ant-design/icons';
|
|
|
-import { Button } from 'antd';
|
|
|
+import { FC, ReactNode, useMemo, useRef, useState } from "react";
|
|
|
+import { UploadFile } from "antd/es/upload/interface";
|
|
|
import {
|
|
|
+ DeleteOutlined,
|
|
|
+ DownloadOutlined,
|
|
|
+ EyeOutlined,
|
|
|
+} from "@ant-design/icons";
|
|
|
+import { Button, Progress, message } from "antd";
|
|
|
+import {
|
|
|
+ DownloadCancelBtn,
|
|
|
+ DownloadProgress,
|
|
|
UploadFileItem,
|
|
|
UploadFileItemActions,
|
|
|
UploadPictureItem,
|
|
|
UploadPictureItemActions,
|
|
|
-} from './style';
|
|
|
+} from "./style";
|
|
|
+import { requestWithPercent } from "../../utils";
|
|
|
|
|
|
export interface DageUploadItemActionsProps {
|
|
|
file: UploadFile;
|
|
|
actions: {
|
|
|
- download: () => void;
|
|
|
preview: () => void;
|
|
|
remove: () => void;
|
|
|
};
|
|
|
isPictureCard?: boolean;
|
|
|
disabled?: boolean;
|
|
|
+ downloadErrorMessage: string;
|
|
|
children: ReactNode;
|
|
|
}
|
|
|
|
|
@@ -27,26 +34,119 @@ export const DageUploadItemActions: FC<DageUploadItemActionsProps> = ({
|
|
|
file,
|
|
|
isPictureCard,
|
|
|
actions,
|
|
|
+ downloadErrorMessage,
|
|
|
}) => {
|
|
|
- const showDownload = (file.url || '').indexOf('http') > -1;
|
|
|
+ const controller = useRef<AbortController | null>(null);
|
|
|
+ const [downloading, setDownloading] = useState(false);
|
|
|
+ /** 下载进度百分比 */
|
|
|
+ const [downloadPercent, setDownloadPercent] = useState(0);
|
|
|
+ /** 显示下载按钮 */
|
|
|
+ const showDownload = (file.url || "").indexOf("http") > -1;
|
|
|
+ /** 显示下载进度条 */
|
|
|
+ const showDownloadProgress = useMemo(
|
|
|
+ () => !isPictureCard && downloading,
|
|
|
+ [isPictureCard, downloading]
|
|
|
+ );
|
|
|
const UploadItem = isPictureCard ? UploadPictureItem : UploadFileItem;
|
|
|
- const UploadItemActions = isPictureCard ? UploadPictureItemActions : UploadFileItemActions;
|
|
|
+ const UploadItemActions = isPictureCard
|
|
|
+ ? UploadPictureItemActions
|
|
|
+ : UploadFileItemActions;
|
|
|
+
|
|
|
+ const handleDownload = async () => {
|
|
|
+ if (!file.url) return;
|
|
|
+
|
|
|
+ try {
|
|
|
+ setDownloading(true);
|
|
|
+ controller.current = new AbortController();
|
|
|
+ const res = await requestWithPercent({
|
|
|
+ url: file.url,
|
|
|
+ option: {
|
|
|
+ signal: controller.current?.signal,
|
|
|
+ },
|
|
|
+ onProcess: (now, all) => {
|
|
|
+ setDownloadPercent(Math.round((now / all) * 100));
|
|
|
+ },
|
|
|
+ });
|
|
|
+
|
|
|
+ // @ts-ignore
|
|
|
+ const blob = new Blob([res]);
|
|
|
+ const url = URL.createObjectURL(blob);
|
|
|
+
|
|
|
+ const link = document.createElement("a");
|
|
|
+ link.href = url;
|
|
|
+ link.target = "_blank";
|
|
|
+ link.download = file.name;
|
|
|
+ link.style.display = "none";
|
|
|
+ document.body.appendChild(link);
|
|
|
+ link.click();
|
|
|
+ document.body.removeChild(link);
|
|
|
+ } catch (err) {
|
|
|
+ if (err instanceof Error && err.name !== "AbortError") {
|
|
|
+ message.error(downloadErrorMessage);
|
|
|
+ }
|
|
|
+ } finally {
|
|
|
+ // 等待进度条动画完成
|
|
|
+ setTimeout(() => {
|
|
|
+ setDownloading(false);
|
|
|
+ setDownloadPercent(0);
|
|
|
+ }, 300);
|
|
|
+ }
|
|
|
+ };
|
|
|
+
|
|
|
+ const handleDownloadCancel = () => {
|
|
|
+ controller.current?.abort();
|
|
|
+ };
|
|
|
|
|
|
return (
|
|
|
- <UploadItem className="dage-upload__item">
|
|
|
+ <UploadItem
|
|
|
+ className="dage-upload__item"
|
|
|
+ showdownloadprogress={showDownloadProgress.toString()}
|
|
|
+ >
|
|
|
{children}
|
|
|
|
|
|
<UploadItemActions className="dage-upload__item__actions">
|
|
|
{isPictureCard && (
|
|
|
- <Button type="text" size="small" icon={<EyeOutlined />} onClick={actions.preview} />
|
|
|
+ <Button
|
|
|
+ type="text"
|
|
|
+ size="small"
|
|
|
+ icon={<EyeOutlined />}
|
|
|
+ onClick={actions.preview}
|
|
|
+ />
|
|
|
)}
|
|
|
{showDownload && (
|
|
|
- <Button type="text" size="small" icon={<DownloadOutlined />} onClick={actions.download} />
|
|
|
+ <Button
|
|
|
+ type="text"
|
|
|
+ size="small"
|
|
|
+ loading={downloading}
|
|
|
+ disabled={downloading}
|
|
|
+ icon={<DownloadOutlined />}
|
|
|
+ onClick={handleDownload}
|
|
|
+ />
|
|
|
)}
|
|
|
{!disabled && (
|
|
|
- <Button type="text" size="small" icon={<DeleteOutlined />} onClick={actions.remove} />
|
|
|
+ <Button
|
|
|
+ type="text"
|
|
|
+ size="small"
|
|
|
+ icon={<DeleteOutlined />}
|
|
|
+ onClick={actions.remove}
|
|
|
+ />
|
|
|
)}
|
|
|
</UploadItemActions>
|
|
|
+
|
|
|
+ {/* 下载进度条 */}
|
|
|
+ {showDownloadProgress && (
|
|
|
+ <DownloadProgress className="dage-upload__item__progress">
|
|
|
+ <Progress
|
|
|
+ size="small"
|
|
|
+ percent={downloadPercent}
|
|
|
+ style={{ margin: 0 }}
|
|
|
+ />
|
|
|
+
|
|
|
+ {downloadPercent < 100 && (
|
|
|
+ <DownloadCancelBtn onClick={handleDownloadCancel} />
|
|
|
+ )}
|
|
|
+ </DownloadProgress>
|
|
|
+ )}
|
|
|
</UploadItem>
|
|
|
);
|
|
|
};
|