Quellcode durchsuchen

reactor:封装页面导出PDF的方法;

zhangchong vor 8 Monaten
Ursprung
Commit
11e8d47678

+ 109 - 11
src/utils/tools.ts

@@ -1,6 +1,8 @@
 import axios from 'axios';
-import dayjs from "dayjs";
-
+import dayjs from 'dayjs';
+import html2canvas from 'html2canvas';
+import JSPDF from 'jspdf';
+import { formatDate } from '@/utils/formatTime';
 /**
  * @description 防抖
  * @param func    功能函数(即要防抖的函数)
@@ -134,11 +136,11 @@ export function downloadFileByStream(res: any, filename?: string) {
 	a.href = URL.createObjectURL(blob);
 	if (!filename) {
 		const fileNameStr = res.headers['content-disposition']?.split(';')[2]?.split('filename*=')[1];
-		if(fileNameStr){
+		if (fileNameStr) {
 			const index = fileNameStr.lastIndexOf("'");
 			const result = fileNameStr.substring(index + 1, fileNameStr.length);
 			filename = decodeURIComponent(result);
-		}else{
+		} else {
 			filename = dayjs().format('YYYYMMDDHHmmss'); // 如果没有文件名,则默认取当前时间
 		}
 	}
@@ -287,7 +289,7 @@ export function handleRowAccordingToProp(row: { [key: string]: any }, prop: stri
  * @param {String} size 需要分割多少份
  * @returns {*}
  * */
-export function  getNeedArr (array: any[], size: number)  {
+export function getNeedArr(array: any[], size: number) {
 	//获取所需指定长度分割的数组;参数1为用于分割的总数组,参数2为分割数组后每个小数组的长度
 	const length = array.length;
 	//判断不是数组,或者size没有设置,size小于1,就返回空数组
@@ -307,14 +309,110 @@ export function  getNeedArr (array: any[], size: number)  {
 	}
 	//输出新数组
 	return result;
-};
+}
 /**
  * @description  判断数组是否在传入的范围内
- * @param {number | string} num 传入的数字
- * @param {number | string} min 最小数
- * @param {number | string} max 最大数
+ * @param {number} num 传入的数字
+ * @param {number} min 最小数
+ * @param {number} max 最大数
  * @returns {*}
  * */
-export function isInRange(num: number | string, min: number | string, max: number | string) {
+export function isInRange(num: number, min: number, max: number) {
 	return num >= min && num <= max;
-}
+}
+/**
+ * @description 获取页面导出的pdf文件  默认导出A4大小的文件
+ * @param fileName 导出文件名
+ * @param className 需要导出的dom的className
+ */
+export function htmlExportPdf(fileName: string, className:string) {
+	return new Promise((resolve) => {
+		const title = fileName || `导出文件${formatDate(new Date(), 'YYYYmmddHHMMSS')}`; // 导出文件名,默认为“标题”
+		const children:any = document.getElementsByClassName(className|| 'pdf-cell');
+		let canvas = <EmptyArrayType>[];
+		let i = 0;
+		const toCanvas = () => {
+			if (children.length) {
+				html2canvas(<HTMLElement>children[i], {
+					scale: 2,
+				}).then((res: any) => {
+					// 计算每个dom的高度,方便后面计算分页
+					res.imgWidth = 190;
+					res.imgHeight = (190 / res.width) * res.height;
+					canvas.push(res);
+					i++;
+					if (canvas.length === children.length) {
+						paging();
+						toPdf();
+					} else {
+						toCanvas();
+					}
+				});
+			}
+		};
+		/**
+		 * [根据dom的高度初步进行分页,会将canvas组装为一个二维数组]
+		 */
+		const paging = () => {
+			const imgArr = <EmptyArrayType>[[]];
+			let pageH = 0; // 页面的高度
+			let allH = 0; // 当前组所有dom的高度和
+			let j = 0;
+			for (let k = 0; k < canvas.length; k++) {
+				// 涉及到k--的操作,使用for循环方便
+				pageH += canvas[k].imgHeight;
+				if (pageH > 257 && canvas[k].imgHeight < 257) {
+					// 当某个页面装不下下一个dom时,则分页
+					imgArr[j][0].allH = allH - canvas[k].imgHeight;
+					allH = pageH = 0;
+					k--;
+					j++;
+					imgArr.push([]);
+				} else {
+					if (canvas[k].imgHeight > 257) {
+						// 特殊情况:某个dom高度大于了页面高度,特殊处理
+						canvas[k].topH = 257 - (pageH - canvas[k].imgHeight); // 该dom顶部距离页面上方的距离
+						pageH = (2 * canvas[k].imgHeight - pageH) % 257;
+						canvas[k].pageH = pageH; // 该dom底部距离页面上方的距离
+					}
+					imgArr[j].push(canvas[k]);
+					allH += canvas[k].imgHeight;
+				}
+				if (k === canvas.length - 1) imgArr[j][0].allH = allH;
+			}
+			canvas = imgArr;
+		};
+		/**
+		 * [生成PDF文件]
+		 */
+		const toPdf = () => {
+			const PDF = new JSPDF('p', 'mm', 'a4');
+			canvas.forEach((page, index) => {
+				let allH = page[0].allH;
+				let position = 0; // pdf页面偏移
+				if (index !== 0 && allH <= 257) PDF.addPage();
+				page.forEach((img: any) => {
+					if (img.imgHeight < 257) {
+						// 当某个dom高度小于页面宽度,直接添加图片
+						PDF.addImage(img.toDataURL('image/jpeg', 1.0), 'JPEG', 10, position + 10, img.imgWidth, img.imgHeight);
+						position += img.imgHeight;
+						allH -= img.imgHeight;
+					} else {
+						// 当某个dom高度大于页面宽度,则需另行处理
+						while (allH > 0) {
+							PDF.addImage(img.toDataURL('image/jpeg', 1.0), 'JPEG', 10, position + 10, img.imgWidth, img.imgHeight);
+							allH -= img.topH || 257;
+							position -= img.topH || 257;
+							img.topH = 0;
+							if (allH > 0) PDF.addPage();
+						}
+						position = img.pageH;
+					}
+				});
+			});
+			PDF.save(title + '.pdf');
+			resolve([]);
+		};
+		toCanvas();
+	});
+}

+ 5 - 15
src/views/statistics/center/detail-report.vue

@@ -13,8 +13,7 @@
 							<div class="report-part-one-content">
 								本报告就形成该事件的线索进行分析,共有{{ state.reportObj?.introduction?.total }}条线索。
 								<span v-for="item in state.reportObj?.introduction?.data">
-									其中【{{ item.sourceChannel }}】{{ item.num }}
-									条,占比{{ item.rate }}%。
+									其中【{{ item.sourceChannel }}】{{ item.num }} 条,占比{{ item.rate }}%。
 								</span>
 							</div>
 						</div>
@@ -81,9 +80,8 @@ import { formatDate } from '@/utils/formatTime';
 import { onMounted, reactive, ref } from 'vue';
 import { centerGenerateAnalysisReport } from '@/api/statistics/center';
 import { useRoute } from 'vue-router';
-import html2canvas from 'html2canvas';
 import mittBus from '@/utils/mitt';
-import JsPDF from 'jspdf';
+import { htmlExportPdf } from '@/utils/tools';
 
 const state = reactive<any>({
 	loading: false,
@@ -531,23 +529,15 @@ const getReportContent = (id: string) => {
 			setHandleOption(handleLegendData, handleData);
 		})
 		.catch((e) => {
-			console.log(e)
+			console.log(e);
 			state.loading = false;
 		});
 };
 // 下载报告
 const downloadReport = () => {
 	state.loading = true;
-	const content: any = document.querySelector('.report-container');
-	html2canvas(content).then((canvas) => {
-		const imgData = canvas.toDataURL('image/png');
-		const pdf = new JsPDF('p', 'mm', 'a4');
-		const imgWidth = pdf.internal.pageSize.getWidth();
-		const imgHeight = (canvas.height * imgWidth) / canvas.width;
-		pdf.addImage(imgData, 'PNG', 0, 0, imgWidth, imgHeight);
-		pdf.save(`【${state.reportObj.analysis.analysisName}】${formatDate(new Date(), 'YYYYmmddHHMMSS')}.pdf`);
-		state.loading = false;
-	});
+	const fileName = `【${state.reportObj.analysis.analysisName}】${formatDate(new Date(), 'YYYYmmddHHMMSS')}.pdf`;
+	htmlExportPdf(fileName, 'report-container').then(()=>{state.loading = false;})
 };
 const route = useRoute();
 // 取消 关闭当前页

+ 0 - 8
src/views/statistics/order/orgHotspot.vue

@@ -138,14 +138,6 @@ const resetQuery = (formEl: FormInstance | undefined) => {
 };
 // 监听 columns 的变化
 const proTableRef = ref<RefType>();
-watch(columns, (newColumns, oldColumns) => {
-  console.log('Columns changed:', { newColumns, oldColumns });
-  nextTick(() => {
-    console.log('proTableRef', proTableRef.value.element)
-    proTableRef.value.element.doLayout();
-  });
-  // 在这里添加其他逻辑,比如重新计算或者做出其他变化
-});
 onMounted(() => {
 	queryList();
 });