添加PDF预览
This commit is contained in:
parent
851b555172
commit
58c3ef2e65
@ -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) {
|
||||
// 检查类型与API中type字段的映射关系 - 扩展匹配模式
|
||||
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 []
|
||||
}
|
||||
|
||||
// 直接使用data字段作为图片URL,过滤掉空值
|
||||
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>
|
||||
|
||||
@ -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>
|
||||
|
||||
Loading…
Reference in New Issue
Block a user