LOADING

加载过慢请开启缓存 浏览器默认开启

Web下载pdf

jspdf+html2canvas

网页pdf

  • @\components\common\HeartReport.vue
<-template->
  <-div class="report-container"->
    <-div id="pdf-content"->
      <-h1 class="title"->心脏诊疗报告<-/h1->
      <-p class="content"->心脏参数:<-/p->
      <-ul class="content"->
        <-li->年龄: {{ docStore.heartParameters.age }}<-/li->
        <-li->性别: {{ docStore.heartParameters.sex }}<-/li->
        <-li->胸部疼痛类型: {{ docStore.heartParameters.cp }}<-/li->
        <-li->血压: {{ docStore.heartParameters.trestbps }}<-/li->
        <-li->胆固醇: {{ docStore.heartParameters.chol }}<-/li->
        <-li->空腹血糖: {{ docStore.heartParameters.fbs }}<-/li->
        <-li->心电图结果: {{ docStore.heartParameters.restecg }}<-/li->
        <-li->最大心跳数: {{ docStore.heartParameters.thalach }}<-/li->
        <-li->运动时是否有心绞痛: {{ docStore.heartParameters.exang }}<-/li->
        <-li->相对于休息的 ST segment 的倾斜度: {{ docStore.heartParameters.oldpeak }}<-/li->
        <-li->透视检查看到的血管数: {{ docStore.heartParameters.ca }}<-/li->
        <-li->缺陷种类: {{ docStore.heartParameters.thal }}<-/li->
      <-/ul->

      <-h2 class="section-title"->诊疗建议:<-/h2->
      <-span v-html="docStore.parsedMessage"-><-/span-> 
    <-/div->
  <-/div->
<-/template->

<-script setup->
import { ref, computed, onMounted } from 'vue';
import useDocStore from '@/stores/document.js'; 
import useImageStore from '@/stores/images.js';  
const docStore = useDocStore();
const imageStore = useImageStore();
import { marked } from 'marked';

// 在组件挂载时调用函数
onMounted(async() =-> {
  await docStore.fetchHeartParameters(imageStore.segImgId)
  await docStore.fetchWenxinAdvice("注意休息早点睡觉")
});


<-/script->

<-style scoped->
@font-face {
  font-family: 'FZFS';
  src: url('@/assets/fonts/fzfs.ttf') format('truetype');
}

.report-container {
  font-family: 'FZFS', 'Times New Roman', sans-serif;
  width: 800px;
  margin: auto;
  padding: 20px;
  box-shadow: 0 2px 12px 0 rgba(0, 0, 0, 0.1);
  border: 1px solid #ddd;
  border-radius: 8px;
  display: flex;
  flex-direction: column;
}

.title {
  font-size: 24px;
  text-align: center;
  margin-bottom: 20px;
}

.section-title {
  font-size: 20px;
  margin-top: 20px;
  margin-bottom: 10px;
}

.content {
  font-size: 16px;
  line-height: 1.6;
}

ul {
  list-style-type: none;
  padding: 0;
}

ul li {
  margin-bottom: 5px;
}
<-/style->
  • @\stores\document.js
import { defineStore } from 'pinia';
import { ref } from 'vue';
import heartimg from '@/assets/heart.png';
import { heartParametersService, wenxinService } from '@/api/doc.js'; // 确保引入服务  
import { downloadPDF } from '@/utils/htmlToPdf.js'; // 新增引入 
import { ChatService } from '@/api/wenxin';
import { marked } from 'marked';

const useDocStore = defineStore('document', () =-> {
    const heartParameters = ref({
        id: 1,
        age: 18,
        sex: '男',
        cp: 0,
        trestbps: 120,
        chol: 200,
        fbs: 0,
        restecg: 0,
        thalach: 150,
        exang: 0,
        oldpeak: 1.0,
        ca: 0,
        thal: 1
    });

    const images = ref([heartimg]);
    const suggestedAdvice = ref("根据心脏参数,建议定期检查并保持健康的生活方式。如有进一步不适,请及时就医。");
    const parsedMessage = ref();

    const fetchHeartParameters = async (fileId) =-> {
        const Id = {
            id: fileId
        };
        console.log(Id);
        try {
            const response = await heartParametersService(Id);
            if (response.code === 0) {
                const data = response.data;

                // 为每个字段设置默认值,如果为空则使用默认值
                heartParameters.value = {
                    id: data.id || heartParameters.value.id,
                    age: data.age !== null ? data.age : 18,
                    sex: data.sex || '男',
                    cp: data.cp !== null ? data.cp : 0,
                    trestbps: data.trestbps !== null ? data.trestbps : 120,
                    chol: data.chol !== null ? data.chol : 200,
                    fbs: data.fbs !== null ? data.fbs : 0,
                    restecg: data.restecg !== null ? data.restecg : 0,
                    thalach: data.thalach !== null ? data.thalach : 150,
                    exang: data.exang !== null ? data.exang : 0,
                    oldpeak: data.oldpeak !== null ? data.oldpeak : 1.0,
                    ca: data.ca !== null ? data.ca : 0,
                    thal: data.thal !== null ? data.thal : 1
                };

                console.log(heartParameters.value)
            } else {
                console.error('Error fetching heart parameters:', response.message);
            }
        } catch (error) {
            console.error('Error fetching heart parameters:', error);
        }
    };

    const fetchWenxinAdvice = async (doctorAdvice) =-> {
        // 构造提问内容
        const message = `
        医生的建议如下:
        "${doctorAdvice}"

        现在,我正在处理一组心脏健康相关的数据,其中包含多个字段:
        - age(年龄):${heartParameters.value.age},表示对象的年龄。
        - sex(性别):${heartParameters.value.sex},表示对象的性别,取值范围为 female 和 male。
        - cp(胸部疼痛类型):${heartParameters.value.cp},痛感由重到轻依次为 typical、atypical、non-anginal 和 asymptomatic。
        - trestbps(血压):${heartParameters.value.trestbps},表示血压数值。
        - chol(胆固醇):${heartParameters.value.chol},表示胆固醇数值。
        - fbs(空腹血糖):${heartParameters.value.fbs},当血糖含量大于120mg/dl时为 true,否则为 false。
        - restecg(心电图结果):${heartParameters.value.restecg},表示心电图结果,取值范围为 norm 和 hyp。
        - thalach(最大心跳数):${heartParameters.value.thalach},表示最大心跳数。
        - exang(运动时是否心绞痛):${heartParameters.value.exang},表示是否在运动时有心绞痛,true 为是,false 为否。
        - oldpeak(运动相对于休息的ST depression):${heartParameters.value.oldpeak},表示 ST 段压数值。
        - slop(心电图ST segment的倾斜度):${heartParameters.value.slop},表示 ST segment 的倾斜度,取值范围为 down、flat 和 up。
        - ca(透视检查看到的血管数):${heartParameters.value.ca},表示透视检查看到的血管数。
        - thal(缺陷种类):${heartParameters.value.thal},表示并发种类,取值范围为 norm、fix 和 rev。
        - status(是否患病):${heartParameters.value.status},表示对象是否患病,取值范围为 buff 和 sick。

        请基于以上信息,并结合医生的建议,站在医生的角度给我提供一个段落形式的建议。可以参考以下模板:

        鉴于您... 我建议您...
    `;

        try {
            // 调用 API 获取响应
            const response = await ChatService({ question: message });
            let advice = response.data; // 假设响应数据在 response.data 中

            // 裁剪建议内容
            const suggestionIndex = advice.indexOf("建议:");
            if (suggestionIndex !== -1) {
                advice = advice.slice(suggestionIndex + 3); // 只保留“建议:”后的内容
            }
            suggestedAdvice.value = advice !== null ? advice : "根据心脏参数,建议定期检查并保持健康的生活方式。如有进一步不适,请及时就医。"; // 假设响应数据在 response.data 中
            console.log(suggestedAdvice.value);
            parsedMessage.value = marked(suggestedAdvice.value);
        } catch (error) {
            console.error('API 请求失败:', error);
        }
    };


    const addImage = (image) =-> {
        images.value.push(image);
    };

    // 生成 PDF 的函数  
    const generatePDF = async () =-> {
        const pdfContent = document.getElementById("pdf-content"); // 替换为你的 HTML 内容的 ID  
        if (!pdfContent) {
            console.error("未找到要渲染的内容");
            return;
        }
        // 调用 utils 下载 PDF 方法  
        await downloadPDF(pdfContent);
    };

    return {
        heartParameters,
        suggestedAdvice,
        parsedMessage,
        fetchHeartParameters,
        fetchWenxinAdvice,
        addImage,
        generatePDF
    };
}, { persist: true });

export default useDocStore;
  • @\utils\htmlToPdf.js
import html2canvas from "html2canvas";
import { jsPDF } from "jspdf";

// 导出 PDF  
export const downloadPDF = async (page) =-> {
    const canvas = await html2canvas(page, {
        useCORS: true, // 允许跨域请求  
        allowTaint: true, // 允许跨域  
        scale: 2, // 设置放大倍数  
        backgroundColor: '#ffffff' // 背景色  
    });

    canvas2PDF(canvas);
};

// 将 canvas 转换为 PDF  
const canvas2PDF = (canvas) =-> {
    const PDF = new jsPDF({
        orientation: 'p', // 参数: l:横向  p:纵向  
        unit: 'mm', // 参数:测量单位("pt","mm", "cm", "m", "in" or "px")  
        format: 'a4' // A4纸  
    });

    const ctx = canvas.getContext('2d');
    const a4w = 190; // A4 宽度  
    const a4h = 277; // A4 高度  
    const imgHeight = Math.floor(a4h * canvas.width / a4w); // 计算每页的高度  
    let renderedHeight = 0;

    while (renderedHeight <- canvas.height) {
        let page = document.createElement("canvas");
        page.width = canvas.width;
        page.height = Math.min(imgHeight, canvas.height - renderedHeight);

        // 用 getImageData 剪裁指定区域  
        page.getContext('2d').putImageData(
            ctx.getImageData(0, renderedHeight, canvas.width, Math.min(imgHeight, canvas.height - renderedHeight)),
            0, 0
        );

        // canvas 转成图片并添加到 PDF  
        PDF.addImage(page.toDataURL('image/jpeg', 0.2), 'JPEG', 10, 10, a4w, Math.min(a4h, a4w * page.height / page.width));

        renderedHeight += imgHeight;

        // 判断是否需要分页  
        if (renderedHeight <- canvas.height) {
            PDF.addPage();
        }
    }

    PDF.save("心脏诊疗报告.pdf"); // 保存 PDF 文件  
    console.log("成功下载文件");
};