添加PDF预览

This commit is contained in:
Euni4U 2025-03-11 16:03:53 +08:00
parent 851b555172
commit 58c3ef2e65
2 changed files with 227 additions and 91 deletions

View File

@ -8,15 +8,34 @@
<div class="image-gallery">
<div class="image-content">
<div
v-if="imageUrls.length > 0"
v-if="mediaFiles.length > 0"
class="image-grid"
:class="{ 'single-image': imageUrls.length === 1 }"
:class="{ 'single-image': mediaFiles.length === 1 }"
>
<div v-for="(url, index) in imageUrls" :key="index" class="image-item">
<div v-for="(file, index) in mediaFiles" :key="index" class="image-item">
<!-- PDF 预览 -->
<div v-if="file.type === 'pdf'" class="pdf-viewer">
<!-- 内嵌 PDF 预览 -->
<div class="pdf-container">
<iframe
:src="file.url"
class="pdf-iframe"
frameborder="0"
></iframe>
</div>
<div class="pdf-actions">
<el-button type="primary" size="small" @click="openPdfInNewTab(file.url)">
<el-icon><FullScreen /></el-icon>
全屏查看
</el-button>
</div>
</div>
<!-- 图片预览 -->
<el-image
:src="url"
v-else
:src="file.url"
:preview-src-list="imageUrls"
:initial-index="index"
:initial-index="getImageIndex(index)"
fit="contain"
class="medical-image"
@error="handleImageError"
@ -46,7 +65,8 @@ import { PatientApi } from '@/api/inspect/inspectpatient'
import { PatientitemsApi } from '@/api/inspect/inspectpatientitems'
import { getUserProfile } from '@/api/system/user/profile'
import { PacsDataApi } from '@/api/inspect/inspectpacsdata'
import { Picture } from '@element-plus/icons-vue'
import { Picture, Document, FullScreen } from '@element-plus/icons-vue'
import VuePdfEmbed from 'vue-pdf-embed'
// props
const props = defineProps({
@ -74,18 +94,23 @@ const isImageDepartment = ref(false)
//
const currentItem = ref(null)
// URL
//
const mediaFiles = ref([])
// PDF
const handlePdfError = (error) => {
console.error('PDF加载失败:', error)
ElMessage.error('PDF加载失败')
}
//
const getImageUrls = async () => {
try {
//
if (!reportData.value.medicalSn) {
console.warn('缺少体检编号(medicalSn)')
return []
}
// PACS
const response = await PacsDataApi.getPacsDataPage({
code: reportData.value.medicalSn,
pageNo: 1,
@ -97,13 +122,9 @@ const getImageUrls = async () => {
}
pacsData.value = response.list
//
let filteredData = response.list
// type
if (props.examType) {
// APItype -
const typePatterns = {
'ultrasound': ['ultrasound', 'us', '超声', '彩超', 'b超', 'doppler'],
'ecg': ['ecg', 'ekg', '心电图', 'electrocardiogram'],
@ -111,41 +132,100 @@ const getImageUrls = async () => {
'urine': ['urine', 'ua', '尿常规', '尿液', 'urinalysis','RT','rt']
}
//
const patterns = typePatterns[props.examType]
if (patterns && patterns.length > 0) {
// 使
filteredData = response.list.filter(item => {
if (!item.type) return false
const itemType = item.type.toLowerCase()
return patterns.some(pattern => itemType.includes(pattern.toLowerCase()))
})
}
}
// ""
if (filteredData.length === 0) {
return []
}
// 使dataURL
const urls = filteredData.map((item) => item.data).filter((url) => url)
//
mediaFiles.value = filteredData.map(item => {
const url = item.data
if (!url) return null
return urls
//
const isPDF = url.toLowerCase().endsWith('.pdf') ||
url.toLowerCase().includes('application/pdf') ||
item.type?.toLowerCase().includes('pdf')
return {
url,
type: isPDF ? 'pdf' : 'image'
}
}).filter(item => item)
console.log('处理后的媒体文件:', mediaFiles.value) //
// URL
imageUrls.value = mediaFiles.value
.filter(file => file.type === 'image')
.map(file => file.url)
return imageUrls.value
} catch (error) {
console.error('获取影像数据失败:', error)
ElMessage.error('获取影像数据失败,请联系管理员')
return []
}
}
//
const getImageIndex = (currentIndex) => {
let imageIndex = 0
for (let i = 0; i < currentIndex; i++) {
if (mediaFiles.value[i].type === 'image') {
imageIndex++
}
}
return imageIndex
}
// PDF
const downloadFile = (url) => {
window.open(url, '_blank')
}
//
const handleImageError = (e) => {
e.target.src = 'https://via.placeholder.com/500x400?text=Image+Not+Found'
}
// PDF
const openPdfInNewTab = (url) => {
const win = window.open('', '_blank')
win.document.write(`
<html>
<head>
<title>PDF查看器</title>
<style>
body {
margin: 0;
padding: 0;
background: #525659;
}
iframe {
width: 100vw;
height: 100vh;
border: none;
}
</style>
</head>
<body>
<iframe src="${url}"></iframe>
</body>
</html>
`)
}
//
const age = computed(() => {
if (!reportData.value.birthday) return ''
@ -392,35 +472,22 @@ const getExamTypeTitle = () => {
.image-grid {
display: grid;
grid-template-columns: repeat(auto-fit, minmax(400px, 1fr));
gap: 10px;
height: 100%;
place-items: center;
grid-template-columns: repeat(auto-fit, minmax(300px, 1fr));
gap: 20px;
padding: 20px;
}
.image-item {
width: 100%;
height: 100%;
max-width: 600px;
max-height: 450px;
aspect-ratio: 4/3;
border-radius: 4px;
overflow: hidden;
transition: transform 0.3s;
}
.image-item:hover {
transform: scale(1.02);
}
.single-image {
height: 400px;
display: flex;
justify-content: center;
flex-direction: column;
align-items: center;
}
.single-image .image-item {
width: 90%;
height: 90%;
max-width: 800px;
margin: 0 auto;
}
.medical-image {
@ -547,4 +614,69 @@ const getExamTypeTitle = () => {
background: #f8f9fa;
color: #909399;
}
/* 更新 PDF 查看器样式 */
.pdf-viewer {
width: 100%;
height: 100%;
display: flex;
flex-direction: column;
background: #f8f9fa;
border-radius: 4px;
position: relative;
overflow: hidden;
}
.pdf-container {
flex: 1;
width: 100%;
height: calc(100% - 40px); /* 减去按钮区域的高度 */
position: relative;
background: #525659;
}
.pdf-iframe {
width: 100%;
height: 100%;
border: none;
background: #fff;
}
.pdf-actions {
height: 40px;
display: flex;
align-items: center;
justify-content: center;
padding: 0 10px;
background: #fff;
border-top: 1px solid #dcdfe6;
}
.pdf-actions .el-button {
display: flex;
align-items: center;
gap: 5px;
}
/* 确保图片网格布局合适 */
.image-grid {
display: grid;
grid-template-columns: repeat(auto-fit, minmax(300px, 1fr));
gap: 20px;
padding: 20px;
}
.image-item {
width: 100%;
height: 400px;
display: flex;
flex-direction: column;
align-items: center;
}
/* 单个文件时的样式 */
.single-image .image-item {
max-width: 800px;
margin: 0 auto;
}
</style>

View File

@ -1275,59 +1275,58 @@ const handleRefresh = async () => {
text: '刷新中...',
background: 'rgba(255, 255, 255, 0.7)'
})
//
selectedPeriod.value = 'reset'
//
selectedPeriod.value = 'today'
showDatePicker.value = false
customDateRange.value = []
//
searchQuery.value = ''
//
try {
//
const existingPatients = await PatientApi.getPatientPage({
pageNo: 1,
pageSize: 100,
examDate: formatDate(new Date())
})
const existingMedicalSns = new Set()
if (existingPatients.list && existingPatients.list.length > 0) {
existingPatients.list.forEach(patient => {
if (patient.medicalSn) {
existingMedicalSns.add(patient.medicalSn)
}
})
}
//
if (existingMedicalSns.size < 5) {
//
await PatientitemsApi.createPatientapiInfo({})
} else {
ElMessage.info('已有足够的患者数据,跳过全量同步')
}
} catch (syncError) {
console.error('同步数据失败:', syncError)
//
}
//
selectedPatient.value = null
//
pageNo.value = 1
//
await getPatientList()
loading.close()
ElMessage.success('刷新成功')
//
const today = new Date()
const todayStart = new Date(today.setHours(0, 0, 0, 0))
const todayEnd = new Date(today.setHours(23, 59, 59, 999))
customDateRange.value = [todayStart, todayEnd]
try {
// 1.
await PatientitemsApi.createPatientapiInfo({})
// 2.
await new Promise(resolve => setTimeout(resolve, 1000))
// 3.
const params = {
pageNo: pageNo.value,
pageSize: pageSize.value,
medicalDateTime: [
`${formatDate(todayStart)} 00:00:00`,
`${formatDate(todayEnd)} 23:59:59`
]
}
const res = await PatientApi.getPatientPage(params)
//
patients.value = res.list
originalPatients.value = res.list
filteredPatients.value = res.list
total.value = res.total
//
patientDataCache.value.clear()
loading.close()
ElMessage.success('刷新成功')
} catch (error) {
loading.close()
console.error('同步数据失败:', error)
ElMessage.error('同步数据失败,请稍后重试')
}
} catch (error) {
console.error('刷新失败:', error)
ElMessage.error('刷新失败')
ElMessage.error('刷新失败,请稍后重试')
}
}
@ -1771,6 +1770,11 @@ const refreshExamData = async () => {
const inspectDoctor = ref('')
const inspectTime = ref('')
//
const isSpecialExam = computed(() => {
return ['ultrasound', 'ecg', 'blood', 'urine'].includes(currentTab.value)
})
</script>
<style scoped>