123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156 |
- import { nextTick, computed } from 'vue';
- import { useMainStore } from '@/store';
- import { ElLoading } from 'element-plus';
- import html2canvas from 'html2canvas';
- import jsPDF from 'jspdf';
- import { showMessage } from './common';
- import { uploadFile } from '@/utils/http';
- import { savePdf } from '@/utils/api';
- const mainStore = useMainStore();
- const expanded = computed(() => mainStore.getExpanded);
- const phone = computed(() => mainStore.getPhone);
- const recordId = computed(() => mainStore.getRecordId);
- const isLoadOver = computed(() => mainStore.getIsLoadOver);
- /**
- * 生成 PDF Blob
- */
- async function generatePDFBlob(
- pdfContent?: HTMLElement,
- showLoading = false
- ): Promise<Blob | null> {
- if (!isLoadOver.value) {
- showMessage({ type: 'warning', message: '数据加载中,请稍后再试' });
- return null;
- }
- let loading: any = null;
- if (showLoading) {
- loading = ElLoading.service({
- lock: true,
- text: '生成报告中...',
- background: 'rgba(0,0,0,0.7)'
- });
- }
- try {
- if (!pdfContent) pdfContent = document.getElementById('Record') as HTMLElement;
- if (!expanded.value) {
- mainStore.setExpanded(true);
- await nextTick();
- }
- await nextTick();
- const canvas = await html2canvas(pdfContent, {
- scale: 2,
- useCORS: true,
- backgroundColor: '#fff'
- });
- const canvasWidth = canvas.width;
- const canvasHeight = canvas.height;
- const pdf = new jsPDF('p', 'mm', 'a4');
- const pageWidth = pdf.internal.pageSize.getWidth();
- const pageHeight = pdf.internal.pageSize.getHeight();
- const ratio = pageWidth / canvasWidth;
- const pagePixelHeight = pageHeight / ratio;
- // 页边距(像素)
- const marginTop = 20; // 仅作用于非第一页
- const marginBottom = 40; // 所有页生效
- let positionY = 0;
- let pageIndex = 0;
- while (positionY < canvasHeight) {
- // 判断是否第一页
- const topMargin = pageIndex === 0 ? 0 : marginTop;
- // 每页实际可容纳的内容高度
- const h = Math.min(
- pagePixelHeight - topMargin - marginBottom,
- canvasHeight - positionY
- );
- const pageCanvas = document.createElement('canvas');
- pageCanvas.width = canvasWidth;
- pageCanvas.height = h;
- const ctx = pageCanvas.getContext('2d');
- ctx?.drawImage(canvas, 0, positionY, canvasWidth, h, 0, 0, canvasWidth, h);
- const imgData = pageCanvas.toDataURL('image/jpeg', 0.95);
- // 添加到 PDF 时,整体往下偏移 topMargin
- pdf.addImage(imgData, 'JPEG', 0, topMargin * ratio, pageWidth, h * ratio);
- positionY += h;
- pageIndex++;
- if (positionY < canvasHeight) pdf.addPage();
- }
- return pdf.output('blob');
- } catch (error) {
- console.error(error);
- showMessage({ type: 'error', message: '生成失败,请稍后再试' });
- return null;
- } finally {
- mainStore.setExpanded(false);
- setTimeout(() => loading && loading.close(), 500);
- }
- }
- /**
- * 下载文件
- */
- function triggerDownload(blob: Blob, filename = 'analysis.pdf') {
- const url = URL.createObjectURL(blob);
- const a = document.createElement('a');
- a.href = url;
- a.download = filename;
- a.click();
- URL.revokeObjectURL(url);
- }
- /**
- * 上传文件
- */
- async function uploadPDFFile(blob: Blob) {
- const file = new File([blob], 'analysis.pdf', { type: 'application/pdf' });
- const uploadRes = await uploadFile(file, { source: 'media', mediaType: 'file' });
- const pdfUrl = uploadRes.data.url;
- await savePdf({
- phone: phone.value,
- id: recordId.value,
- pdfUrl
- });
- return pdfUrl;
- }
- /**
- * 统一入口:生成 PDF
- * @param pdfContent - PDF内容DOM
- * @param mode - "manual" 手动下载 | "auto" 自动下载并上传
- */
- export async function handlePDF(pdfContent?: HTMLElement, mode: 'manual' | 'auto' = 'manual') {
- const blob = await generatePDFBlob(pdfContent, true);
- if (!blob) return;
- // 下载
- triggerDownload(blob);
- // 自动模式下再上传
- if (mode === 'auto') {
- try {
- await uploadPDFFile(blob);
- // showMessage({ type: 'success', message: '报告已下载并上传成功' });
- } catch (err) {
- // showMessage({ type: 'error', message: '报告上传失败' });
- throw err;
- }
- }
- }
|