增加pdf预览组件
parent
d7ccfda275
commit
e566e8132b
|
|
@ -0,0 +1,18 @@
|
|||
import type { CSSProperties, FC } from "react";
|
||||
|
||||
export interface PdfProps {
|
||||
/** pdf 文件地址 */
|
||||
file: string;
|
||||
/** 是否显示弹窗 */
|
||||
visible?: boolean;
|
||||
/** 关闭弹窗的方法 */
|
||||
onCancel?: () => void;
|
||||
/** 是否使用内联模式,true为不使用弹窗,默认为false */
|
||||
inline?: boolean;
|
||||
/** 内联模式下的样式 */
|
||||
style?: CSSProperties;
|
||||
}
|
||||
|
||||
declare const Pdf: FC<PdfProps>;
|
||||
|
||||
export default Pdf;
|
||||
|
|
@ -0,0 +1,84 @@
|
|||
import { Button, message, Modal, Spin } from "antd";
|
||||
import { useState } from "react";
|
||||
import { Document, Page, pdfjs } from "react-pdf";
|
||||
import { getFileUrl } from "../../utils/index";
|
||||
|
||||
function Pdf(props) {
|
||||
const {
|
||||
visible = false,
|
||||
onCancel,
|
||||
file,
|
||||
inline = false,
|
||||
style = {},
|
||||
} = props;
|
||||
|
||||
const fileUrl = getFileUrl();
|
||||
const [numPages, setNumPages] = useState(0);
|
||||
const [pdfWidth, setPdfWidth] = useState(600);
|
||||
const [loading, setLoading] = useState(true);
|
||||
|
||||
pdfjs.GlobalWorkerOptions.workerSrc = new URL(
|
||||
"pdfjs-dist/build/pdf.worker.min.mjs",
|
||||
import.meta.url,
|
||||
).toString();
|
||||
|
||||
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 && (
|
||||
<div style={{ display: "flex", justifyContent: "center", alignItems: "center", height: "80vh" }}>
|
||||
<Spin size="large" />
|
||||
</div>
|
||||
)}
|
||||
<div style={{ height: "88vh", overflowY: "auto", padding: "24px", ...style }}>
|
||||
<Document
|
||||
file={fileUrl + file}
|
||||
onLoadSuccess={onDocumentLoadSuccess}
|
||||
onLoadError={onDocumentLoadError}
|
||||
>
|
||||
{
|
||||
Array.from({ length: numPages }).map((el, index) => (
|
||||
<Page key={`page_${index + 1}`} pageNumber={index + 1} onLoadSuccess={onPageLoadSuccess} />
|
||||
))
|
||||
}
|
||||
</Document>
|
||||
</div>
|
||||
</>
|
||||
);
|
||||
|
||||
// 如果是内联模式,直接返回PDF内容
|
||||
if (inline) {
|
||||
return renderPdfContent();
|
||||
}
|
||||
|
||||
// 默认弹窗模式
|
||||
return (
|
||||
<Modal
|
||||
open={visible}
|
||||
width={pdfWidth + 100}
|
||||
title="PDF预览"
|
||||
onCancel={onCancel}
|
||||
footer={<Button onClick={onCancel}>关闭</Button>}
|
||||
>
|
||||
{renderPdfContent()}
|
||||
</Modal>
|
||||
);
|
||||
}
|
||||
|
||||
export default Pdf;
|
||||
|
|
@ -0,0 +1,18 @@
|
|||
import type { FC } from "react";
|
||||
|
||||
export interface PreviewPdfProps {
|
||||
/** 文件列表,和 name、url 冲突 */
|
||||
files?: { [p: string]: any }[];
|
||||
/** 文件名字段名,传入 files 时会优先查找是否存在 name、fileName */
|
||||
nameKey?: string;
|
||||
/** 文件路径字段名,传入 files 时会优先查找是否存在 filePath */
|
||||
urlKey?: string;
|
||||
/** 单个文件名,和 files 冲突 */
|
||||
name?: string;
|
||||
/** 单个文件路径,和 files 冲突 */
|
||||
url?: string;
|
||||
}
|
||||
|
||||
declare const PreviewPdf: FC<PreviewPdfProps>;
|
||||
|
||||
export default PreviewPdf;
|
||||
|
|
@ -0,0 +1,76 @@
|
|||
import { Button, Space } from "antd";
|
||||
import { useState } from "react";
|
||||
import Pdf from "../Pdf";
|
||||
|
||||
const PreviewPdf = (props) => {
|
||||
const {
|
||||
files = [],
|
||||
nameKey = "",
|
||||
urlKey = "",
|
||||
name = "",
|
||||
url = "",
|
||||
} = props;
|
||||
|
||||
const [visible, setVisible] = useState(false);
|
||||
const [src, setSrc] = useState("");
|
||||
|
||||
const previewPdf = (src) => {
|
||||
setVisible(true);
|
||||
setSrc(src);
|
||||
};
|
||||
|
||||
const onCancel = () => {
|
||||
setVisible(false);
|
||||
setSrc("");
|
||||
};
|
||||
|
||||
// 单个文件预览模式
|
||||
if (files.length === 0 && name && url) {
|
||||
return (
|
||||
<>
|
||||
<Space>
|
||||
<span>{name}</span>
|
||||
<Button type="primary" size="small" onClick={() => previewPdf(url)}>
|
||||
预览
|
||||
</Button>
|
||||
</Space>
|
||||
<Pdf
|
||||
visible={visible}
|
||||
file={src}
|
||||
onCancel={onCancel}
|
||||
/>
|
||||
</>
|
||||
);
|
||||
}
|
||||
|
||||
// 多文件预览模式
|
||||
if (files.length > 0 && !name && !url) {
|
||||
return (
|
||||
<>
|
||||
{files.map(item => (
|
||||
<div key={item.filePath || item[urlKey]} style={{ marginTop: 5 }}>
|
||||
<Space>
|
||||
<span>{item.name || item.fileName || item[nameKey]}</span>
|
||||
<Button
|
||||
type="primary"
|
||||
size="small"
|
||||
onClick={() => previewPdf(item.filePath || item[urlKey])}
|
||||
>
|
||||
预览
|
||||
</Button>
|
||||
</Space>
|
||||
</div>
|
||||
))}
|
||||
<Pdf
|
||||
visible={visible}
|
||||
file={src}
|
||||
onCancel={onCancel}
|
||||
/>
|
||||
</>
|
||||
);
|
||||
}
|
||||
|
||||
return null;
|
||||
};
|
||||
|
||||
export default PreviewPdf;
|
||||
|
|
@ -28,6 +28,7 @@
|
|||
"antd": "^5.27.6",
|
||||
"dayjs": "^1.11.18",
|
||||
"lodash-es": "^4.17.21",
|
||||
"react": "^18.3.1"
|
||||
"react": "^18.3.1",
|
||||
"react-pdf": "^10.2.0"
|
||||
}
|
||||
}
|
||||
|
|
|
|||
Loading…
Reference in New Issue