imeeting/components/PDFViewer/PDFViewer.jsx

138 lines
3.7 KiB
React
Raw Normal View History

import { useState, useMemo } from 'react'
import { Document, Page, pdfjs } from 'react-pdf'
import { Button, Space, InputNumber, message, Spin } from 'antd'
import {
LeftOutlined,
RightOutlined,
ZoomInOutlined,
ZoomOutOutlined,
} from '@ant-design/icons'
import 'react-pdf/dist/Page/AnnotationLayer.css'
import 'react-pdf/dist/Page/TextLayer.css'
import './PDFViewer.css'
// 配置 PDF.js worker - 使用本地文件
pdfjs.GlobalWorkerOptions.workerSrc = '/pdf-worker/pdf.worker.min.mjs'
function PDFViewer({ url, filename }) {
const [numPages, setNumPages] = useState(null)
const [pageNumber, setPageNumber] = useState(1)
const [scale, setScale] = useState(1.0)
// 使用 useMemo 避免不必要的重新加载
const fileConfig = useMemo(() => ({ url }), [url])
const onDocumentLoadSuccess = ({ numPages }) => {
setNumPages(numPages)
setPageNumber(1)
}
const onDocumentLoadError = (error) => {
message.error('PDF文件加载失败')
}
const goToPrevPage = () => {
setPageNumber((prev) => Math.max(prev - 1, 1))
}
const goToNextPage = () => {
setPageNumber((prev) => Math.min(prev + 1, numPages))
}
const zoomIn = () => {
setScale((prev) => Math.min(prev + 0.2, 3.0))
}
const zoomOut = () => {
setScale((prev) => Math.max(prev - 0.2, 0.5))
}
const handlePageChange = (value) => {
if (value >= 1 && value <= numPages) {
setPageNumber(value)
}
}
return (
<div className="pdf-viewer-container">
{/* 工具栏 */}
<div className="pdf-toolbar">
<Space>
<Button
icon={<LeftOutlined />}
onClick={goToPrevPage}
disabled={pageNumber <= 1}
size="small"
>
上一页
</Button>
<Space.Compact>
<InputNumber
min={1}
max={numPages || 1}
value={pageNumber}
onChange={handlePageChange}
size="small"
style={{ width: 60 }}
/>
<Button size="small" disabled>
/ {numPages || 0}
</Button>
</Space.Compact>
<Button
icon={<RightOutlined />}
onClick={goToNextPage}
disabled={pageNumber >= numPages}
size="small"
>
下一页
</Button>
</Space>
<Space>
<Button icon={<ZoomOutOutlined />} onClick={zoomOut} size="small">
缩小
</Button>
<span style={{ minWidth: 50, textAlign: 'center' }}>
{Math.round(scale * 100)}%
</span>
<Button icon={<ZoomInOutlined />} onClick={zoomIn} size="small">
放大
</Button>
</Space>
</div>
{/* PDF内容区 */}
<div className="pdf-content">
<Document
file={fileConfig}
onLoadSuccess={onDocumentLoadSuccess}
onLoadError={onDocumentLoadError}
loading={
<div className="pdf-loading">
<Spin size="large" />
<div style={{ marginTop: 16 }}>正在加载PDF...</div>
</div>
}
error={<div className="pdf-error">PDF加载失败请稍后重试</div>}
>
<Page
pageNumber={pageNumber}
scale={scale}
renderTextLayer={true}
renderAnnotationLayer={true}
loading={
<div className="pdf-loading">
<Spin size="large" />
<div style={{ marginTop: 16 }}>正在渲染页面...</div>
</div>
}
/>
</Document>
</div>
</div>
)
}
export default PDFViewer