469 lines
15 KiB
Vue
469 lines
15 KiB
Vue
<template>
|
||
<el-dialog
|
||
v-model="dialogVisible"
|
||
title="体检报告预览"
|
||
width="90%"
|
||
top="3vh"
|
||
:destroy-on-close="true"
|
||
:close-on-click-modal="false"
|
||
@close="handleClose"
|
||
class="report-preview-dialog"
|
||
>
|
||
<div class="iframe-container">
|
||
<iframe
|
||
v-if="dialogVisible"
|
||
src="/templates/report-template.html"
|
||
frameborder="0"
|
||
style="width: 100%; height: 100%; border: none"
|
||
@load="handleIframeLoad"
|
||
></iframe>
|
||
</div>
|
||
<template #footer>
|
||
<span class="dialog-footer">
|
||
<el-button @click="handleClose">关闭</el-button>
|
||
<el-button type="primary" @click="handlePrint"> 打印报告 </el-button>
|
||
</span>
|
||
</template>
|
||
</el-dialog>
|
||
</template>
|
||
|
||
<script setup lang="ts">
|
||
import type { App } from 'vue'
|
||
import { ref, defineProps, defineEmits, watch } from 'vue'
|
||
import { PatientApi } from '@/api/inspect/inspectpatient/index'
|
||
import Message from '@/layout/components/Message/src/Message.vue'
|
||
|
||
const props = defineProps({
|
||
visible: {
|
||
type: Boolean,
|
||
default: false
|
||
},
|
||
reportData: {
|
||
type: Object,
|
||
default: () => ({})
|
||
}
|
||
})
|
||
|
||
const emit = defineEmits(['update:visible', 'close'])
|
||
|
||
const dialogVisible = ref(props.visible)
|
||
|
||
watch(
|
||
() => props.visible,
|
||
(newVal) => {
|
||
dialogVisible.value = newVal
|
||
if (newVal) {
|
||
// 当对话框显示时,设置iframe内容
|
||
setTimeout(() => {
|
||
// setIframeContent()
|
||
}, 100) // 给一点时间让DOM更新
|
||
}
|
||
}
|
||
)
|
||
|
||
watch(
|
||
() => dialogVisible.value,
|
||
(newVal) => {
|
||
emit('update:visible', newVal)
|
||
}
|
||
)
|
||
|
||
const handleIframeLoad = async () => {
|
||
const iframe = document.querySelector('iframe')
|
||
const reportData = await PatientApi.getReportAll(props.reportData.medicalSn)
|
||
console.log('reportData', reportData)
|
||
if (iframe && iframe.contentWindow) {
|
||
const doc = iframe.contentWindow.document
|
||
|
||
// 更新首页体检编号
|
||
const reportTitle = doc.querySelector('.report-title')
|
||
if (reportTitle) {
|
||
reportTitle.textContent = `体检编号:${reportData.medicalSn || '--'}`
|
||
}
|
||
|
||
// 更新个人信息
|
||
// 姓名
|
||
const nameContent = doc.querySelector('.person_detail:nth-child(1) .person_content')
|
||
if (nameContent) nameContent.textContent = reportData.pName || '--'
|
||
|
||
// 性别
|
||
const sexContent = doc.querySelector('.person_detail:nth-child(2) .person_content')
|
||
if (sexContent) sexContent.textContent = reportData.gender || '--'
|
||
|
||
let age = '--'
|
||
// 年龄 - 从出生日期计算
|
||
const ageContent = doc.querySelector('.person_detail:nth-child(3) .person_content')
|
||
if (ageContent) {
|
||
if (reportData.birthday) {
|
||
const birthDate = new Date(reportData.birthday)
|
||
const today = new Date()
|
||
let calculatedAge = today.getFullYear() - birthDate.getFullYear()
|
||
const m = today.getMonth() - birthDate.getMonth()
|
||
if (m < 0 || (m === 0 && today.getDate() < birthDate.getDate())) {
|
||
calculatedAge--
|
||
}
|
||
age = calculatedAge.toString()
|
||
}
|
||
ageContent.textContent = age
|
||
}
|
||
|
||
// 单位
|
||
const companyContent = doc.querySelector('.person_detail:nth-child(4) .person_content')
|
||
if (companyContent) companyContent.textContent = reportData.cardId || '--'
|
||
|
||
// 联系电话
|
||
const phoneContent = doc.querySelector('.person_detail:nth-child(5) .person_content')
|
||
if (phoneContent) phoneContent.textContent = reportData.phoneNum|| '--'
|
||
|
||
// 体检日期
|
||
const examDateContent = doc.querySelector('.person_detail:nth-child(6) .person_content')
|
||
if (examDateContent) {
|
||
const date = reportData.medicalDateTime ? new Date(reportData.medicalDateTime) : null
|
||
const formattedDate = date
|
||
? `${date.getFullYear()}年${String(date.getMonth() + 1).padStart(2, '0')}月${String(date.getDate()).padStart(2, '0')}日`
|
||
: '--'
|
||
examDateContent.textContent = formattedDate
|
||
}
|
||
// 更新头像
|
||
const avatarImg = doc.getElementById('avatar-image')
|
||
if (avatarImg) {
|
||
avatarImg.src = reportData.headPicUrl || ''
|
||
}
|
||
|
||
// 更新前言中的姓名 - 修复选择器
|
||
const prefaceGreeting = doc.querySelector('.preface-greeting .underline')
|
||
if (prefaceGreeting) {
|
||
prefaceGreeting.textContent = reportData.pName || '________'
|
||
console.log('已更新前言姓名为:', reportData.pName)
|
||
} else {
|
||
console.log('未找到前言姓名元素,尝试使用备用选择器')
|
||
// 备用选择器
|
||
const altPrefaceGreeting = doc.querySelector('.preface-content .underline')
|
||
if (altPrefaceGreeting) {
|
||
altPrefaceGreeting.textContent = reportData.pName || '________'
|
||
console.log('使用备用选择器更新前言姓名为:', reportData.pName)
|
||
} else {
|
||
console.error('无法找到前言姓名元素')
|
||
}
|
||
}
|
||
|
||
// 更新一般检查数据(身高等)
|
||
const generalData = reportData.data.reduce((acc, item) => {
|
||
acc[item.itemName] = item
|
||
return acc
|
||
}, {})
|
||
|
||
const tbody = doc.querySelector('.general-exam .exam-table tbody')
|
||
if (tbody) {
|
||
tbody.innerHTML = `
|
||
<tr><td>体温</td><td>${generalData['体温']?.itemResult || '--'}℃</td></tr>
|
||
<tr><td>脉率</td><td>${generalData['脉率']?.itemResult || '--'}次/分</td></tr>
|
||
<tr><td>呼吸频率</td><td>${generalData['呼吸频率']?.itemResult || '--'}次/分</td></tr>
|
||
<tr><td>血压</td><td>${generalData['血压']?.itemResult || '--'} mmHg</td></tr>
|
||
<tr><td>腰围</td><td>${generalData['腰围']?.itemResult || '--'} cm</td></tr>
|
||
<tr><td>身高</td><td>${generalData['身高']?.itemResult || '--'} cm</td></tr>
|
||
<tr><td>体重</td><td>${generalData['体重']?.itemResult || '--'} kg</td></tr>
|
||
<tr><td>体质指数(BMI)</td><td>${generalData['BMI']?.itemResult || '--'} kg/m²</td></tr>
|
||
`
|
||
}
|
||
|
||
// 更新一般检查小结
|
||
const generalSummary = doc.querySelector('.general-exam .report-summary p')
|
||
if (generalSummary) {
|
||
// 只取身高项目的 analyse 作为小结
|
||
const heightData = generalData['身高']
|
||
generalSummary.textContent = heightData?.analyse || '暂无小结'
|
||
}
|
||
|
||
// 更新超声检查报告
|
||
const ultrasoundData = reportData.data.find(
|
||
(item) => item.itemName === '超声' || item.itemName === 'US'
|
||
)
|
||
if (ultrasoundData) {
|
||
// 更新超声检查报告内容
|
||
const ultrasoundSummary = doc.querySelector('.report-item.ultrasound-exam .report-summary')
|
||
if (ultrasoundSummary) {
|
||
// 解析 analyse 字段(格式:"检查所见:xxx\n检查结果:xxx")
|
||
const findings = ultrasoundData.analyse.split('\n')[0].replace('检查所见:', '') || ''
|
||
const conclusion = ultrasoundData.analyse.split('\n')[1].replace('检查结果:', '') || ''
|
||
|
||
ultrasoundSummary.innerHTML = `
|
||
<p><strong>【所见】</strong><br>${findings}</p>
|
||
<p><strong>【所得】</strong><br>${conclusion}</p>
|
||
`
|
||
} else {
|
||
console.error('未找到超声检查小结元素')
|
||
}
|
||
|
||
// 更新超声检查PDF链接
|
||
if (ultrasoundData.data) {
|
||
// 为PDF URL添加参数
|
||
const pdfUrl = ultrasoundData.data + '#toolbar=0&navpanes=0&view=Fit'
|
||
|
||
// 更新屏幕显示的iframe
|
||
const iframeElement = doc.querySelector('.ultrasound-exam .screen-only iframe')
|
||
if (iframeElement) {
|
||
iframeElement.src = pdfUrl
|
||
} else {
|
||
console.error('未找到超声检查iframe元素')
|
||
}
|
||
|
||
// 更新打印用的PDF容器
|
||
const pdfContainer = doc.querySelector('.ultrasound-exam .print-only.pdf-container')
|
||
if (pdfContainer) {
|
||
pdfContainer.setAttribute('data-pdf-url', pdfUrl)
|
||
} else {
|
||
console.error('未找到超声检查PDF容器')
|
||
}
|
||
}
|
||
}
|
||
|
||
// 更新其他检查报告
|
||
// 尿常规
|
||
const urineData = reportData.data.find((item) => item.itemName === '尿常规')
|
||
if (urineData) {
|
||
const urineSummary = doc.querySelector('.report-item:nth-of-type(6) .report-summary p')
|
||
if (urineSummary) {
|
||
urineSummary.textContent = urineData.analyse || ''
|
||
}
|
||
}
|
||
|
||
// 更新生化检查
|
||
const biochemData = reportData.data.find((item) => item.itemName === '生化')
|
||
if (biochemData) {
|
||
// 改为第7个report-item(原4→7)
|
||
const biochemSummary = doc.querySelector('.report-item:nth-of-type(7) .report-summary p')
|
||
if (biochemSummary) {
|
||
biochemSummary.textContent = biochemData.analyse || ''
|
||
} else {
|
||
console.error('未找到生化检查小结元素')
|
||
}
|
||
}
|
||
|
||
// 更新血常规
|
||
const bloodData = reportData.data.find((item) => item.itemName === '血常规')
|
||
if (bloodData) {
|
||
// 改为第8个report-item(原5→8)
|
||
const bloodSummary = doc.querySelector('.report-item:nth-of-type(8) .report-summary p')
|
||
if (bloodSummary) {
|
||
bloodSummary.textContent = bloodData.analyse || ''
|
||
} else {
|
||
console.error('未找到血常规小结元素')
|
||
}
|
||
}
|
||
|
||
// 获取所有报告标题中的第二个span(填充值所在位置)
|
||
const reportTitles = doc.querySelectorAll('.report-title > div > span:nth-child(2)')
|
||
// 更新每个填充值
|
||
reportTitles.forEach((span) => {
|
||
span.textContent =
|
||
`${reportData.medicalSn || '--'} ` +
|
||
`${reportData.pName || '--'} ` +
|
||
`${reportData.gender || '--'} ` +
|
||
`${age || '--'}岁`
|
||
})
|
||
|
||
// 更新心电图
|
||
const ecgData = reportData.data.find((item) => item.itemName === '心电图')
|
||
if (ecgData) {
|
||
// 改为第9个report-item(原last-child→9)
|
||
const ecgSummary = doc.querySelector('.report-item:nth-of-type(9) .report-summary')
|
||
if (ecgSummary) {
|
||
ecgSummary.innerHTML = `
|
||
<p><strong>【所见】</strong><br>${ecgData.analyse.split('\n')[0].replace('检查所见:', '') || ''}</p>
|
||
<p><strong>【所得】</strong><br>${ecgData.analyse.split('\n')[1].replace('检查结果:', '') || ''}</p>
|
||
`
|
||
} else {
|
||
console.error('未找到心电图小结元素')
|
||
}
|
||
}
|
||
|
||
// 设置体质辨识结果
|
||
const constitutionValue = doc.querySelector('#constitution-result .constitution-value')
|
||
if (constitutionValue) {
|
||
constitutionValue.textContent = reportData.zybs || '--'
|
||
}
|
||
|
||
// 更新汇总结果
|
||
const summaryElement = doc.getElementById('summary-year')
|
||
if (summaryElement) {
|
||
summaryElement.textContent = reportData.summaryResult || '--'
|
||
}
|
||
|
||
// 更新图片和 PDF 链接
|
||
reportData.data.forEach((item) => {
|
||
if (item.data) {
|
||
let reportTitle = ''
|
||
switch (item.pacsDataType) {
|
||
case 'cbc':
|
||
reportTitle = '血常规检查报告'
|
||
break
|
||
case 'ecg':
|
||
reportTitle = '心电图检查报告'
|
||
break
|
||
case 'bt':
|
||
reportTitle = '生化检查报告'
|
||
break
|
||
case 'US':
|
||
reportTitle = '超声检查报告'
|
||
break
|
||
case 'rt':
|
||
reportTitle = '尿常规检查报告'
|
||
break
|
||
default:
|
||
break
|
||
}
|
||
if (reportTitle) {
|
||
const reportSection = Array.from(doc.querySelectorAll('.report-item')).find((section) => {
|
||
const titleElement = section.querySelector('.report-title')
|
||
return titleElement && titleElement.textContent?.trim().includes(reportTitle)
|
||
})
|
||
if (reportSection) {
|
||
// 为PDF URL添加参数
|
||
const pdfUrl = item.data + '#toolbar=0&navpanes=0&view=Fit'
|
||
console.log('pdfUrl', pdfUrl)
|
||
// 更新 iframe src
|
||
const iframeElement = reportSection.querySelector('.screen-only iframe')
|
||
if (iframeElement) {
|
||
iframeElement.src = pdfUrl
|
||
}
|
||
|
||
// 更新图片 src(如果是图片,保持原样)
|
||
const img = reportSection.querySelector('img')
|
||
if (img) {
|
||
img.src = item.data
|
||
}
|
||
|
||
// 更新打印时显示的 PDF 容器的 data-pdf-url
|
||
const pdfContainer = reportSection.querySelector('.print-only.pdf-container')
|
||
if (pdfContainer) {
|
||
pdfContainer.setAttribute('data-pdf-url', pdfUrl)
|
||
}
|
||
}
|
||
}
|
||
}
|
||
})
|
||
}
|
||
}
|
||
|
||
// 修改等待渲染完成的函数,添加更多检查和日志
|
||
const waitForAllPDFsRendered = () => {
|
||
return new Promise((resolve) => {
|
||
const checkRendering = () => {
|
||
const containers = document.querySelectorAll('.pdf-container')
|
||
let allDone = true
|
||
containers.forEach((container, index) => {
|
||
const imageContainer = container.querySelector('.pdf-image-container')
|
||
const img = imageContainer?.querySelector('img')
|
||
// 更严格的检查条件
|
||
if (
|
||
!imageContainer ||
|
||
!img ||
|
||
!img.complete ||
|
||
imageContainer.style.display !== 'block' ||
|
||
!img.src
|
||
) {
|
||
allDone = false
|
||
}
|
||
})
|
||
|
||
if (allDone) {
|
||
resolve(true)
|
||
} else {
|
||
setTimeout(checkRendering, 1000) // 增加检查间隔到1秒
|
||
}
|
||
}
|
||
|
||
checkRendering()
|
||
})
|
||
}
|
||
|
||
// 修改打印处理函数
|
||
const handlePrint = async () => {
|
||
const iframe = document.querySelector('iframe')
|
||
if (iframe && iframe.contentWindow) {
|
||
const iframeDoc = iframe.contentWindow.document
|
||
|
||
// 显示加载提示
|
||
const loadingMessage = iframeDoc.createElement('div')
|
||
loadingMessage.style.position = 'fixed'
|
||
loadingMessage.style.top = '50%'
|
||
loadingMessage.style.left = '50%'
|
||
loadingMessage.style.transform = 'translate(-50%, -50%)'
|
||
loadingMessage.style.padding = '20px'
|
||
loadingMessage.style.background = 'rgba(0, 0, 0, 0.7)'
|
||
loadingMessage.style.color = 'white'
|
||
loadingMessage.style.borderRadius = '5px'
|
||
loadingMessage.style.zIndex = '9999'
|
||
loadingMessage.innerHTML = '正在准备打印,请稍候...'
|
||
iframeDoc.body.appendChild(loadingMessage)
|
||
|
||
try {
|
||
// 获取所有需要转换的PDF容器
|
||
const containers = iframeDoc.querySelectorAll('.pdf-container')
|
||
|
||
// 执行所有PDF转换
|
||
for (const container of containers) {
|
||
const pdfUrl = container.getAttribute('data-pdf-url')
|
||
if (pdfUrl) {
|
||
await iframe.contentWindow.renderPDFAsImage(pdfUrl, container)
|
||
}
|
||
}
|
||
iframeDoc.body.removeChild(loadingMessage)
|
||
|
||
// 执行打印
|
||
iframe.contentWindow?.print()
|
||
handleClose()
|
||
} catch (error) {
|
||
console.error('PDF转换过程出错:', error)
|
||
iframeDoc.body.removeChild(loadingMessage)
|
||
}
|
||
}
|
||
}
|
||
|
||
const handleClose = () => {
|
||
dialogVisible.value = false
|
||
emit('close')
|
||
}
|
||
</script>
|
||
|
||
<style scoped>
|
||
.dialog-footer {
|
||
padding: 10px 0;
|
||
}
|
||
|
||
.iframe-container {
|
||
height: 80vh;
|
||
overflow: hidden; /* 改为hidden,去掉滚动条 */
|
||
}
|
||
|
||
:deep(.el-dialog__body) {
|
||
padding: 0;
|
||
overflow: hidden; /* 确保对话框内容区域也没有滚动条 */
|
||
}
|
||
|
||
:deep(.el-dialog__header) {
|
||
margin-right: 0;
|
||
padding: 15px 20px;
|
||
border-bottom: 1px solid #e0e0e0;
|
||
}
|
||
|
||
:deep(.el-dialog__footer) {
|
||
border-top: 1px solid #e0e0e0;
|
||
padding: 10px 20px;
|
||
}
|
||
|
||
:deep(.report-preview-dialog) {
|
||
max-height: 94vh;
|
||
margin: 3vh auto !important;
|
||
display: flex;
|
||
flex-direction: column;
|
||
overflow: hidden; /* 确保整个对话框没有滚动条 */
|
||
}
|
||
|
||
:deep(.el-dialog__body) {
|
||
flex: 1;
|
||
overflow: hidden; /* 再次确保没有滚动条 */
|
||
}
|
||
</style>
|