- 实现pdf下载(安装依赖:jsPDF、jspdf-autotable、html2canvas)
/**
* report.ts
*/
import React, { FC, ReactElement, useState, useEffect } from 'react';
import { useStores } from '@/store';
import { observer } from 'mobx-react';
import { Modal, Table } from 'antd';
import styles from './index.less';
import jsPDF from 'jspdf';
import 'jspdf-autotable';
import './PingFang-normal.js'; // 字体文件,解决中文乱码问题,下文有具体解决方案
import html2canvas from 'html2canvas';
interface IProps {
visible: boolean;
onChangeVisible: (visible: boolean) => void;
}
const Report: FC<IProps> = (props): ReactElement => {
let store = useStores();
const { visible, onChangeVisible } = props;
const tableColumn = ['序号', '姓名', '年龄', '地址'];
const dataSource = [ ]
for (let i = 0; i < 46; i++) {
dataSource.push({
key: i,
name: `Edward King ${i}`,
age: 32,
address: `London, Park Lane no. ${i}`,
});
}
const columns = [
{
title: '序号',
dataIndex: 'NO',
render(text: string, record: any, index: number) {
return <span>{index + 1}</span>;
},
},
{
title: '姓名',
dataIndex: 'name',
key: 'name',
},
{
title: '年龄',
dataIndex: 'age',
key: 'age',
},
{
title: '地址',
dataIndex: 'address',
key: 'address',
},
];
const handleOk = async () => {
const doc = new jsPDF('p', 'pt', 'a4');
doc.setFont('PingFang', 'normal', 'normal');
const reportTitleDom = document.getElementById('reportTitle');
const tableRows: any = [];
dataSource.forEach((ticket) => {
const ticketData = [ticket.key, ticket.name, ticket.age, ticket.address];
tableRows.push(ticketData);
});
if (!reportTitleDom) return;
// 加第二个参数: { allowTaint: true, scale: 2 }为了提高生成的图片的清晰度
html2canvas(reportTitleDom, { allowTaint: true, scale: 2 }).then(
(canvas: any) => {
const imgData = canvas.toDataURL('image/png');
doc.addImage(imgData, 'JPEG', 20, 20, 555, 110);
doc.autoTable(tableColumn, tableRows, {
startY: 140,
showFoot: 'lastPage',
theme: 'plain',
margin: 20,
styles: {
font: 'PingFang',
fontStyle: 'normal',
halign: 'left',
cellPadding: 11,
cellWidth: 139,
lineWidth: 1,
lineColor: '#f4f9fa',
},
headStyles: {
fillColor: '#f4f9fa',
textColor: '#333',
fontStyle: 'bold',
},
bodyStyles: { fillColor: '#fff', textColor: '#333' },
didDrawPage: (data: any) => {
//插入页脚注释
//data.table.finalY 表格最大可容纳y轴坐标,超出时将根据设置决定是否另取一页.在页面需要分页时出现
let tabHeigth = data.cursor.y,
tabMarginTop = data.settings.margin.top,
tabSize = data.table.finalY - tabMarginTop, //表格最大Y轴-表格顶部距离得到每页表格的最大值
tabMarginLeft = data.settings.margin.left;
//是否分页 有分页时才有该属性finalY
if (data.table.finalY)
if (data.pageNumber !== Math.ceil(tabHeigth / tabSize)) return; //如果需要每一页都显示页尾则注释该行代码
doc.setFontSize(10);
doc.setTextColor('#E00000');
doc.text(
'*页脚注释',
tabMarginLeft,
data.cursor.y + 20,
);
},
});
doc.save('报告.pdf');
onChangeVisible(false);
},
);
};
const handleCancel = () => {
onChangeVisible(false);
};
return (
<Modal
title="pdf报告"
visible={visible}
onOk={handleOk}
onCancel={handleCancel}
width={900}
okText="下载报告(pdf)"
cancelText="关闭"
forceRender
maskClosable={false}
>
<div className={styles.reportWrap} id="printArea">
{/* reportTitle部分用canvas生成pdf */}
<div id="reportTitle">
<div className={styles.titleWrap}>
<div className={styles.leftTitleWrap}>
<span className={styles.line}></span>
<span className={styles.title}>title信息</span>
</div>
</div>
<div className={styles.patientDetail}>
<div className={styles.detailItem}>号码:TY20211125001</div>
<div className={styles.detailItem}>姓名:尼古拉斯凯奇</div>
<div className={styles.detailItem}>性别:男</div>
<div className={styles.detailItem}>年龄:33岁</div>
</div>
<div className={styles.titleWrap}>
<div className={styles.leftTitleWrap}>
<span className={styles.line}></span>
<span className={styles.title}>table数据</span>
</div>
<div className={styles.rightTitleWrap}>展示展示</div>
</div>
</div>
{/* tableWrap部分用jspdf-autotable生成pdf */}
<div className={styles.tableWrap}>
<Table
dataSource={dataSource}
columns={columns}
pagination={false}
scroll={{ y: 350 }}
/>
</div>
<div className={styles.notes} id="reportNotes">
*页脚注释
</div>
</div>
</Modal>
);
};
export default observer(Report);
/**
* index.less
*/
.reportWrap {
font-family: PingFang SC-Medium, PingFang SC;
font-size: 14px;
font-weight: 400;
::-webkit-scrollbar {
width: 8px;
height: 8px;
}
::-webkit-scrollbar-track {
background-color: #f0f2f3;
border-radius: 2em;
}
::-webkit-scrollbar-thumb {
background-color: #d3dde0;
border-radius: 2em;
}
.titleWrap {
background: #f4f9fa;
color: #23a3ab;
font-weight: 500;
font-size: 16px;
padding: 8px;
display: flex;
justify-content: space-between;
align-items: center;
margin-bottom: 16px;
.leftTitleWrap {
display: flex;
align-items: center;
.line {
display: inline-block;
width: 2px;
background: #23a3ab;
height: 15px;
}
.title {
padding-left: 10px;
}
}
.rightTitleWrap {
font-weight: 400;
color: #999999;
}
}
.patientDetail {
display: flex;
color: #333333;
padding: 0 16px 32px 16px;
.detailItem {
margin-right: 48px;
}
}
.tableWrap {
padding: 0 16px;
}
.notes {
text-align: right;
color: #e00000;
padding: 12px 16px 36px 0;
}
}
- 解决中文乱码问题
1、去这里下载一个ttf字体文件,或者自己从别处下载(字体文件越小越好)
2、去这里将项目clone下来,打开 fontconverter/fontconverter.html,操作如下图
3、将生成的 .js 文件引入项目
import { jsPDF } from 'jspdf';
var font = 'AAdfjsklfsl'; # ttf字体文件的base64编码
var callAddFont = function () {
this.addFileToVFS('PingFang-normal.ttf', font);
this.addFont('PingFang-normal.ttf', 'PingFang', 'normal');
};
jsPDF.API.events.push(['addFonts', callAddFont]);