2025-12-22 14:47:41 +08:00
|
|
|
|
import { useFullscreen } from "ahooks";
|
|
|
|
|
|
import { Button, message, Modal, Spin } from "antd";
|
|
|
|
|
|
import { useRef, useState } from "react";
|
2025-10-22 17:54:38 +08:00
|
|
|
|
import { Document, Page, pdfjs } from "react-pdf";
|
2025-11-08 15:52:06 +08:00
|
|
|
|
import useDownloadFile from "../../hooks/useDownloadFile";
|
2025-12-22 14:47:41 +08:00
|
|
|
|
import { getFileUrl } from "../../utils";
|
|
|
|
|
|
import "react-pdf/dist/Page/AnnotationLayer.css";
|
|
|
|
|
|
import "react-pdf/dist/Page/TextLayer.css";
|
|
|
|
|
|
import "./index.less";
|
2025-10-22 17:54:38 +08:00
|
|
|
|
|
2025-10-28 15:16:58 +08:00
|
|
|
|
/**
|
|
|
|
|
|
* PDF查看组件
|
|
|
|
|
|
*/
|
2025-10-22 17:54:38 +08:00
|
|
|
|
function Pdf(props) {
|
|
|
|
|
|
const {
|
|
|
|
|
|
visible = false,
|
|
|
|
|
|
onCancel,
|
|
|
|
|
|
file,
|
2025-11-08 15:52:06 +08:00
|
|
|
|
name,
|
2025-10-22 17:54:38 +08:00
|
|
|
|
inline = false,
|
|
|
|
|
|
style = {},
|
|
|
|
|
|
} = props;
|
|
|
|
|
|
|
|
|
|
|
|
const fileUrl = getFileUrl();
|
|
|
|
|
|
const [numPages, setNumPages] = useState(0);
|
|
|
|
|
|
const [pdfWidth, setPdfWidth] = useState(600);
|
|
|
|
|
|
const [loading, setLoading] = useState(true);
|
|
|
|
|
|
|
2025-12-22 14:47:41 +08:00
|
|
|
|
const fullscreenRef = useRef(null);
|
|
|
|
|
|
|
|
|
|
|
|
const [isFullscreen, { enterFullscreen, exitFullscreen }] = useFullscreen(fullscreenRef);
|
|
|
|
|
|
const { downloadFile } = useDownloadFile();
|
|
|
|
|
|
|
2025-12-17 16:56:26 +08:00
|
|
|
|
pdfjs.GlobalWorkerOptions.workerSrc = `//unpkg.com/pdfjs-dist@${pdfjs.version}/build/pdf.worker.min.mjs`;
|
2025-10-22 17:54:38 +08:00
|
|
|
|
|
|
|
|
|
|
const onDocumentLoadSuccess = ({ numPages }) => {
|
|
|
|
|
|
setNumPages(numPages);
|
|
|
|
|
|
setLoading(false);
|
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
|
|
const onDocumentLoadError = () => {
|
|
|
|
|
|
setLoading(false);
|
|
|
|
|
|
message.error("加载 PDF 文件失败");
|
|
|
|
|
|
if (onCancel)
|
|
|
|
|
|
onCancel();
|
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
|
|
const onPageLoadSuccess = ({ width }) => {
|
|
|
|
|
|
setPdfWidth(width);
|
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
|
|
// 内联模式的PDF内容
|
|
|
|
|
|
const renderPdfContent = () => (
|
|
|
|
|
|
<>
|
|
|
|
|
|
{loading && (
|
2025-12-22 14:56:49 +08:00
|
|
|
|
<div style={{ display: "flex", justifyContent: "center", alignItems: "center", height: "72vh" }}>
|
2025-10-22 17:54:38 +08:00
|
|
|
|
<Spin size="large" />
|
|
|
|
|
|
</div>
|
|
|
|
|
|
)}
|
2025-12-22 14:47:41 +08:00
|
|
|
|
<div style={{ height: isFullscreen ? "calc(100vh - 40px - 24px - 8px - 32px - 12px)" : "72vh", overflowY: "auto", padding: "24px", ...style }}>
|
2025-10-22 17:54:38 +08:00
|
|
|
|
<Document
|
2025-11-06 14:31:25 +08:00
|
|
|
|
file={!file.includes(fileUrl) ? fileUrl + file : file}
|
2025-10-22 17:54:38 +08:00
|
|
|
|
onLoadSuccess={onDocumentLoadSuccess}
|
|
|
|
|
|
onLoadError={onDocumentLoadError}
|
|
|
|
|
|
>
|
|
|
|
|
|
{
|
2025-12-22 14:47:41 +08:00
|
|
|
|
Array.from({ length: numPages }).map((_, index) => (
|
2025-10-22 17:54:38 +08:00
|
|
|
|
<Page key={`page_${index + 1}`} pageNumber={index + 1} onLoadSuccess={onPageLoadSuccess} />
|
|
|
|
|
|
))
|
|
|
|
|
|
}
|
|
|
|
|
|
</Document>
|
|
|
|
|
|
</div>
|
|
|
|
|
|
</>
|
|
|
|
|
|
);
|
|
|
|
|
|
|
|
|
|
|
|
// 如果是内联模式,直接返回PDF内容
|
|
|
|
|
|
if (inline) {
|
|
|
|
|
|
return renderPdfContent();
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2025-11-08 15:52:06 +08:00
|
|
|
|
const onDownloadFile = () => {
|
2025-12-22 14:47:41 +08:00
|
|
|
|
isFullscreen && exitFullscreen();
|
|
|
|
|
|
downloadFile({
|
|
|
|
|
|
url: file,
|
|
|
|
|
|
name,
|
2025-11-08 15:52:06 +08:00
|
|
|
|
});
|
|
|
|
|
|
};
|
|
|
|
|
|
|
2025-10-22 17:54:38 +08:00
|
|
|
|
// 默认弹窗模式
|
|
|
|
|
|
return (
|
2025-12-22 14:47:41 +08:00
|
|
|
|
<div ref={fullscreenRef}>
|
|
|
|
|
|
<Modal
|
|
|
|
|
|
style={{ top: isFullscreen ? 0 : 100, maxWidth: isFullscreen ? "100vw" : "calc(100vw - 32px)", paddingBottom: isFullscreen ? 0 : 24 }}
|
|
|
|
|
|
open={visible}
|
|
|
|
|
|
maskClosable={false}
|
|
|
|
|
|
width={isFullscreen ? "100vw" : pdfWidth + 100}
|
|
|
|
|
|
title="PDF预览"
|
|
|
|
|
|
onCancel={() => {
|
|
|
|
|
|
isFullscreen && exitFullscreen();
|
|
|
|
|
|
onCancel();
|
|
|
|
|
|
}}
|
|
|
|
|
|
getContainer={false}
|
|
|
|
|
|
footer={[
|
|
|
|
|
|
<Button
|
|
|
|
|
|
key="cancel"
|
|
|
|
|
|
onClick={() => {
|
|
|
|
|
|
isFullscreen && exitFullscreen();
|
|
|
|
|
|
onCancel();
|
|
|
|
|
|
}}
|
|
|
|
|
|
>
|
|
|
|
|
|
关闭
|
|
|
|
|
|
</Button>,
|
2025-12-22 14:56:49 +08:00
|
|
|
|
!loading && <Button
|
2025-12-22 14:47:41 +08:00
|
|
|
|
key="fullScreen"
|
|
|
|
|
|
onClick={() => {
|
|
|
|
|
|
isFullscreen ? exitFullscreen() : enterFullscreen();
|
|
|
|
|
|
}}
|
|
|
|
|
|
>
|
|
|
|
|
|
{isFullscreen ? "退出全屏" : "全屏"}
|
|
|
|
|
|
</Button>,
|
|
|
|
|
|
<Button key="download" type="primary" onClick={onDownloadFile}>下载</Button>,
|
|
|
|
|
|
]}
|
|
|
|
|
|
>
|
|
|
|
|
|
{renderPdfContent()}
|
|
|
|
|
|
</Modal>
|
|
|
|
|
|
</div>
|
2025-10-22 17:54:38 +08:00
|
|
|
|
);
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
export default Pdf;
|