diff --git a/components/Pdf/index.d.ts b/components/Pdf/index.d.ts new file mode 100644 index 0000000..7fb7e98 --- /dev/null +++ b/components/Pdf/index.d.ts @@ -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; + +export default Pdf; diff --git a/components/Pdf/index.js b/components/Pdf/index.js new file mode 100644 index 0000000..a8c7621 --- /dev/null +++ b/components/Pdf/index.js @@ -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 && ( +
+ +
+ )} +
+ + { + Array.from({ length: numPages }).map((el, index) => ( + + )) + } + +
+ + ); + + // 如果是内联模式,直接返回PDF内容 + if (inline) { + return renderPdfContent(); + } + + // 默认弹窗模式 + return ( + 关闭} + > + {renderPdfContent()} + + ); +} + +export default Pdf; diff --git a/components/PreviewPdf/index.d.ts b/components/PreviewPdf/index.d.ts new file mode 100644 index 0000000..75ac15e --- /dev/null +++ b/components/PreviewPdf/index.d.ts @@ -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; + +export default PreviewPdf; diff --git a/components/PreviewPdf/index.js b/components/PreviewPdf/index.js new file mode 100644 index 0000000..b7a57f9 --- /dev/null +++ b/components/PreviewPdf/index.js @@ -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 ( + <> + + {name} + + + + + ); + } + + // 多文件预览模式 + if (files.length > 0 && !name && !url) { + return ( + <> + {files.map(item => ( +
+ + {item.name || item.fileName || item[nameKey]} + + +
+ ))} + + + ); + } + + return null; +}; + +export default PreviewPdf; diff --git a/package.json b/package.json index 3466d2c..a725be2 100644 --- a/package.json +++ b/package.json @@ -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" } }