这个东西做的我真的是头昏脑涨
主要需求是,upload上传pdf,pdf转图片格式展示,以图片格式上传到后端
封装了组件代码
父组件直接放就可以了
使用的插件pdfjs-dist,版本是 "pdfjs-dist": "2.5.207",
import React, { useState, useEffect, useRef } from 'react';
import { Spin, Pagination } from 'antd';
import { Form, UploadProps, Image } from "antd";
import { message, Modal, Upload, Button } from "antd";
import { useDispatch, useSelector } from 'react-redux';
import type RootState from '@/types/rootState';
import { getToken } from "@/utils/login";
import config from "@/utils/config";
import type { RcFile, UploadChangeParam } from "antd/lib/upload";
import type { UploadFile } from "antd/es/upload/interface";
import { Toast } from "antd-mobile";
import { LoadingOutlined, PlusOutlined } from "@ant-design/icons";
import type { PurchaseOrderAction } from "@/pages/purchase/purchaseOrder/model";
var pdfjsLib = require('pdfjs-dist/build/pdf.js');
import 'pdfjs-dist/build/pdf.worker.entry';interface PdfViewerProps {url: string;
}
const formItemLayout = {labelCol: {span: 3,},wrapperCol: {span: 12,},
};
const PdfViewer = () => {const [pageNumbers, setPageNumbers] = useState(1);const [loading, setLoading] = useState(true);const [supportImages, setSupportImages] = useState<string[]>([]);const [uploadingImages, setUploadingImages] = useState<boolean>(false);const [supportFileList, setSupportFileList] = useState<UploadFile[]>([]);const [previewImage, setPreviewImage] = useState<string>('');const [previewVisible, setPreviewVisible] = useState<boolean>(false);const dispatch = useDispatch();const pdfRef: any = useRef(null);const processPage = async (pageNumbers: any, pdfFile: any, pdfName: any, uid: any, type: any) => {// 转base64let canvas: any = document.getElementById('pdf');let canvasContext = canvas.getContext('2d');const page = await pdfFile.getPage(pageNumbers);const viewport = page.getViewport({ scale: 5 });canvas.height = viewport.height;canvas.width = viewport.width;canvasContext.clearRect(0, 0, canvas.width, canvas.height);const renderContext = {canvasContext: canvasContext,viewport: viewport,rotate: 90,};await page.render(renderContext).promise;// 转base64const imgUrl = canvas.toDataURL('image/jpg');const thumbimg = dataURLtoFile(imgUrl, 'image/png');const fileOfBlob = new File([thumbimg], `${pdfName}.png`);const formData = new FormData();formData.append('file', fileOfBlob, `${pdfName}.png`);formData.append('dir', 'purchase');const response = await fetch(config.api.pictureUpload, {method: 'POST',headers: {'x-access-token': getToken(),},body: formData,});if (response.ok) {const data = await response.json();return {uid: uid,name: `${pdfName}.png`,status: 'done',url: data.data,};}return null;}// pdf转图片const processAllPages = async (numpage: any, pdfFile: any, pdfName: any, uid: any, type: any) => {const arr: any = [];const pdfImgArr:any = []// pdf可能不止一个页面,循环提取for (let i = 1; i < numpage; i++) {const imgData = await processPage(i, pdfFile, pdfName, uid, type);if (imgData) {arr.push(imgData);pdfImgArr.push(imgData.url)}}setUploadingImages(false);// 因为我需要跟别的接口上传的图合并 ,所以做了存储dispatch<PurchaseOrderAction>({type: 'purchaseOrder/updateState',payload: {pdfImgArr},})setSupportFileList(arr);};const uploadProps: UploadProps = {action: config.api.pictureUpload,headers: {'x-access-token': getToken()!,},data: { dir: 'purchase' },listType: 'picture-card',showUploadList: false,};// 生成图片格式function dataURLtoFile(dataURI: any, type: any) {let binary = atob(dataURI.split(',')[1]);let array = [];for (let i = 0; i < binary.length; i++) {array.push(binary.charCodeAt(i));}return new Blob([new Uint8Array(array)], { type: type });}// 上传的文件 const handleUploadSupportImages = (file: UploadChangeParam<UploadFile<any>>) => {let name = file.file.name.split('.')[0]let uid = file.file.uidlet type = 'image/png'const reader = new FileReader()reader.readAsArrayBuffer(file.file.originFileObj)reader.onload = function () {const pdfFile = reader.result;let loadingTask = pdfjsLib.getDocument(pdfFile);loadingTask.promise.then((pdf: any) => {setPageNumbers(pdf.numPages);let numpage = Number(pdf.numPages) + 1if (numpage > 9) {Toast.fail("超过数量限制!");return}processAllPages(numpage, pdf, name, uid, type);}).catch((error: any) => {console.log(error);}).finally(() => {setLoading(false);});}if (file.file.status === 'uploading') {setUploadingImages(true);return;}if (file.file.status === 'done') {const { response } = file.file;supportImages.push(response.data);setSupportImages(supportImages);if (response.success) {dispatch<PurchaseOrderAction>({type: 'deliveryDetail/updateState',payload: {},});setUploadingImages(false);} else {message.error(response.message);setUploadingImages(false);}}};//预览const handlePreview = (file: UploadFile<any>) => {setPreviewImage(file.url! || file.thumbUrl!)setPreviewVisible(true)}const uploadImagesButton = (<div>{uploadingImages ? <LoadingOutlined /> : <PlusOutlined />}<div style={{ marginTop: 8 }}>上传pdf</div></div>);const handleCancelPreview = () => {setPreviewVisible(false)}return (<><Form.Item{...formItemLayout}label="导入pdf文件"hasFeedbackstyle={{ marginTop: '15px' }}><Upload{...uploadProps}showUploadList={true}multiple={true}accept='.pdf'maxCount={1}onPreview={handlePreview}onChange={(info) => {handleUploadSupportImages(info)}}showUploadList={{showRemoveIcon:false}}fileList={supportFileList}>{uploadImagesButton}</Upload></Form.Item><Modalopen={previewVisible}title='图片预览'footer={null}onCancel={handleCancelPreview}><img alt="example" style={{ width: '100%' }} src={previewImage} /></Modal><canvas id="pdf" style={{ width: '0px' }} /></>);
};export default PdfViewer;
写的可能还有些需要优化的,但是我已经累了,暂时先这样吧