新增科室录入界面区分以及接口
This commit is contained in:
parent
9c6305a0d2
commit
81762466b2
49
src/api/inspect/ inspectlisdata/index.ts
Normal file
49
src/api/inspect/ inspectlisdata/index.ts
Normal file
@ -0,0 +1,49 @@
|
|||||||
|
import request from '@/config/axios'
|
||||||
|
|
||||||
|
// lis抓取数据 VO
|
||||||
|
export interface LisDataVO {
|
||||||
|
id: number // 主键
|
||||||
|
code: string // 体检编号
|
||||||
|
type: string // 类型
|
||||||
|
equipmentManufacturerModel: string // 设备厂商型号
|
||||||
|
item: string // 项目
|
||||||
|
personName: string // 检测者姓名
|
||||||
|
time: Date // 检测时间
|
||||||
|
data: string // 数据
|
||||||
|
remark: string // 备注
|
||||||
|
delFlag: number // 是否删除(0-未删除,1-已删除)
|
||||||
|
createId: string // 创建人
|
||||||
|
}
|
||||||
|
|
||||||
|
// lis抓取数据 API
|
||||||
|
export const LisDataApi = {
|
||||||
|
// 查询lis抓取数据分页
|
||||||
|
getLisDataPage: async (params: any) => {
|
||||||
|
return await request.get({ url: `/inspect/lis-data/page`, params })
|
||||||
|
},
|
||||||
|
|
||||||
|
// 查询lis抓取数据详情
|
||||||
|
getLisData: async (id: number) => {
|
||||||
|
return await request.get({ url: `/inspect/lis-data/get?id=` + id })
|
||||||
|
},
|
||||||
|
|
||||||
|
// 新增lis抓取数据
|
||||||
|
createLisData: async (data: LisDataVO) => {
|
||||||
|
return await request.post({ url: `/inspect/lis-data/create`, data })
|
||||||
|
},
|
||||||
|
|
||||||
|
// 修改lis抓取数据
|
||||||
|
updateLisData: async (data: LisDataVO) => {
|
||||||
|
return await request.put({ url: `/inspect/lis-data/update`, data })
|
||||||
|
},
|
||||||
|
|
||||||
|
// 删除lis抓取数据
|
||||||
|
deleteLisData: async (id: number) => {
|
||||||
|
return await request.delete({ url: `/inspect/lis-data/delete?id=` + id })
|
||||||
|
},
|
||||||
|
|
||||||
|
// 导出lis抓取数据 Excel
|
||||||
|
exportLisData: async (params) => {
|
||||||
|
return await request.download({ url: `/inspect/lis-data/export-excel`, params })
|
||||||
|
},
|
||||||
|
}
|
50
src/api/inspect/inspectpacsdata/index.ts
Normal file
50
src/api/inspect/inspectpacsdata/index.ts
Normal file
@ -0,0 +1,50 @@
|
|||||||
|
import request from '@/config/axios'
|
||||||
|
|
||||||
|
// pacs抓取数据 VO
|
||||||
|
export interface PacsDataVO {
|
||||||
|
id: number // 主键
|
||||||
|
code: string // 体检编号
|
||||||
|
data: string // 数据
|
||||||
|
time: Date // 监测时间
|
||||||
|
equipmentManufacturerModel: string // 设备厂商型号
|
||||||
|
item: string // 项目
|
||||||
|
type: string // 类型
|
||||||
|
remark: string // 备注
|
||||||
|
delFlag: number // 是否删除(0-未删除,1-已删除)
|
||||||
|
createId: string // 创建人
|
||||||
|
createTime: Date // 创建时间
|
||||||
|
personName: string // 检测者姓名
|
||||||
|
}
|
||||||
|
|
||||||
|
// pacs抓取数据 API
|
||||||
|
export const PacsDataApi = {
|
||||||
|
// 查询pacs抓取数据分页
|
||||||
|
getPacsDataPage: async (params: any) => {
|
||||||
|
return await request.get({ url: `/inspect/pacs-data/page`, params })
|
||||||
|
},
|
||||||
|
|
||||||
|
// 查询pacs抓取数据详情
|
||||||
|
getPacsData: async (id: number) => {
|
||||||
|
return await request.get({ url: `/inspect/pacs-data/get?id=` + id })
|
||||||
|
},
|
||||||
|
|
||||||
|
// 新增pacs抓取数据
|
||||||
|
createPacsData: async (data: PacsDataVO) => {
|
||||||
|
return await request.post({ url: `/inspect/pacs-data/create`, data })
|
||||||
|
},
|
||||||
|
|
||||||
|
// 修改pacs抓取数据
|
||||||
|
updatePacsData: async (data: PacsDataVO) => {
|
||||||
|
return await request.put({ url: `/inspect/pacs-data/update`, data })
|
||||||
|
},
|
||||||
|
|
||||||
|
// 删除pacs抓取数据
|
||||||
|
deletePacsData: async (id: number) => {
|
||||||
|
return await request.delete({ url: `/inspect/pacs-data/delete?id=` + id })
|
||||||
|
},
|
||||||
|
|
||||||
|
// 导出pacs抓取数据 Excel
|
||||||
|
exportPacsData: async (params) => {
|
||||||
|
return await request.download({ url: `/inspect/pacs-data/export-excel`, params })
|
||||||
|
},
|
||||||
|
}
|
@ -447,22 +447,15 @@ const fetchPatientsByDate = async () => {
|
|||||||
`${formatDate(endDate)} 23:59:59`
|
`${formatDate(endDate)} 23:59:59`
|
||||||
],
|
],
|
||||||
// 添加搜索关键词
|
// 添加搜索关键词
|
||||||
pname: searchQuery.value || undefined
|
pname: searchQuery.value || undefined,
|
||||||
|
// 添加收费状态筛选参数
|
||||||
|
chargeStatus: chargeStatus.value === 'paid' ? '1' : '0'
|
||||||
}
|
}
|
||||||
|
|
||||||
const res = await PatientApi.getPatientPage(params)
|
const res = await PatientApi.getPatientPage(params)
|
||||||
|
|
||||||
// 在前端根据chargeType字段筛选
|
patients.value = res.list || []
|
||||||
if (chargeStatus.value === 'unpaid') {
|
total.value = res.total || 0
|
||||||
// 筛选未收费的患者(chargeType为null、undefined或空字符串)
|
|
||||||
patients.value = res.list.filter(patient => !patient.chargeType || patient.chargeType === '')
|
|
||||||
} else {
|
|
||||||
// 筛选已收费的患者(chargeType有值且不为空字符串)
|
|
||||||
patients.value = res.list.filter(patient => patient.chargeType && patient.chargeType !== '')
|
|
||||||
}
|
|
||||||
|
|
||||||
// 更新总数
|
|
||||||
total.value = patients.value.length
|
|
||||||
|
|
||||||
// 如果没有查询到患者,清除选中状态
|
// 如果没有查询到患者,清除选中状态
|
||||||
if (patients.value.length === 0) {
|
if (patients.value.length === 0) {
|
||||||
@ -576,8 +569,10 @@ onMounted(() => {
|
|||||||
// 设置默认为今日
|
// 设置默认为今日
|
||||||
const today = new Date()
|
const today = new Date()
|
||||||
selectedPeriod.value = 'today'
|
selectedPeriod.value = 'today'
|
||||||
const todayStart = new Date(today.setHours(0, 0, 0, 0))
|
const todayStart = new Date(today)
|
||||||
const todayEnd = new Date(today.setHours(23, 59, 59, 999))
|
todayStart.setHours(0, 0, 0, 0)
|
||||||
|
const todayEnd = new Date(today)
|
||||||
|
todayEnd.setHours(23, 59, 59, 999)
|
||||||
customDateRange.value = [todayStart, todayEnd]
|
customDateRange.value = [todayStart, todayEnd]
|
||||||
|
|
||||||
// 获取今日数据
|
// 获取今日数据
|
||||||
|
710
src/views/Department-entry/CT.vue
Normal file
710
src/views/Department-entry/CT.vue
Normal file
@ -0,0 +1,710 @@
|
|||||||
|
<template>
|
||||||
|
<div class="ct-container">
|
||||||
|
<!-- 基本信息 -->
|
||||||
|
<div class="basic-info">
|
||||||
|
<div class="photo-box">
|
||||||
|
<img v-if="reportData.headPicUrl" :src="reportData.headPicUrl" alt="头像" class="photo"/>
|
||||||
|
<div v-else class="no-photo">个人照片</div>
|
||||||
|
</div>
|
||||||
|
<div class="info-grid">
|
||||||
|
<div class="info-row">
|
||||||
|
<div class="info-item">
|
||||||
|
<label>体检编号:</label>
|
||||||
|
<span>{{ reportData.medicalSn }}</span>
|
||||||
|
</div>
|
||||||
|
<div class="info-item">
|
||||||
|
<label>身份证号:</label>
|
||||||
|
<span>{{ reportData.cardId }}</span>
|
||||||
|
</div>
|
||||||
|
<div class="info-item">
|
||||||
|
<label>姓名:</label>
|
||||||
|
<span>{{ reportData.pname }}</span>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="info-row">
|
||||||
|
<div class="info-item">
|
||||||
|
<label>性别:</label>
|
||||||
|
<span>{{ reportData.gender }}</span>
|
||||||
|
</div>
|
||||||
|
<div class="info-item">
|
||||||
|
<label>年龄:</label>
|
||||||
|
<span>{{ age }}岁</span>
|
||||||
|
</div>
|
||||||
|
<div class="info-item">
|
||||||
|
<label>电话:</label>
|
||||||
|
<span>{{ reportData.phoneNum }}</span>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<!-- 检查结果部分 -->
|
||||||
|
<div class="exam-results">
|
||||||
|
<!-- 检查项目标签 -->
|
||||||
|
<div class="exam-tabs">
|
||||||
|
<div
|
||||||
|
v-for="tab in examTabs"
|
||||||
|
:key="tab.id"
|
||||||
|
:class="['tab-item', { active: currentTab === tab.id }]"
|
||||||
|
@click="switchTab(tab.id)"
|
||||||
|
>
|
||||||
|
<div class="tab-indicator" :style="{ background: tab.color }"></div>
|
||||||
|
<span>{{ tab.name }}</span>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<!-- 影像检查结果 -->
|
||||||
|
<div class="image-results">
|
||||||
|
<!-- 影像图片展示区 -->
|
||||||
|
<div class="image-gallery">
|
||||||
|
<div class="gallery-title">影像图片</div>
|
||||||
|
<div class="image-container">
|
||||||
|
<div v-if="imageUrls.length > 0" class="image-grid">
|
||||||
|
<div v-for="(url, index) in imageUrls" :key="index" class="image-item">
|
||||||
|
<el-image
|
||||||
|
:src="url"
|
||||||
|
:preview-src-list="imageUrls"
|
||||||
|
:initial-index="index"
|
||||||
|
fit="contain"
|
||||||
|
class="medical-image"
|
||||||
|
@error="handleImageError"
|
||||||
|
:preview-teleported="true"
|
||||||
|
>
|
||||||
|
<template #error>
|
||||||
|
<div class="image-error">
|
||||||
|
<el-icon><Picture /></el-icon>
|
||||||
|
<div class="error-text">加载失败</div>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
</el-image>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div v-else class="no-images">
|
||||||
|
<el-empty description="暂无影像资料" />
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<!-- 检查所见和诊断 -->
|
||||||
|
<div class="findings-diagnosis-container">
|
||||||
|
<div class="findings-section">
|
||||||
|
<div class="section-title">检查所见</div>
|
||||||
|
<textarea
|
||||||
|
v-model="imageFinding"
|
||||||
|
placeholder="请输入检查所见"
|
||||||
|
class="findings-textarea"
|
||||||
|
:readonly="isReadOnly"
|
||||||
|
></textarea>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="diagnosis-section">
|
||||||
|
<div class="section-title">影像诊断</div>
|
||||||
|
<textarea
|
||||||
|
v-model="imageDiagnosis"
|
||||||
|
placeholder="请输入影像诊断"
|
||||||
|
class="diagnosis-textarea"
|
||||||
|
:readonly="isReadOnly"
|
||||||
|
></textarea>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<!-- 底部操作栏 -->
|
||||||
|
<div class="action-footer">
|
||||||
|
<div class="footer-content">
|
||||||
|
<div class="doctor-info">
|
||||||
|
<span>检查医生:{{ user?.nickname || '暂无' }}</span>
|
||||||
|
<span>检查日期:{{ formattedMedicalDateTime }}</span>
|
||||||
|
</div>
|
||||||
|
<div class="action-buttons">
|
||||||
|
<button class="action-btn" @click="checkEditPermission">同步结果</button>
|
||||||
|
<button class="action-btn">报告预览</button>
|
||||||
|
<button class="action-btn" @click="checkEditPermission">弃检</button>
|
||||||
|
<button
|
||||||
|
v-if="!isReadOnly"
|
||||||
|
class="action-btn primary"
|
||||||
|
@click="handleSaveResults"
|
||||||
|
>
|
||||||
|
保存结果
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script setup>
|
||||||
|
import { ref, computed, watch, onMounted } from 'vue'
|
||||||
|
import { ElMessage, ElMessageBox, ElLoading } from 'element-plus'
|
||||||
|
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'
|
||||||
|
|
||||||
|
// 添加props定义
|
||||||
|
const props = defineProps({
|
||||||
|
patient: {
|
||||||
|
type: Object,
|
||||||
|
required: true
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
|
// 添加响应式引用
|
||||||
|
const reportData = ref({})
|
||||||
|
const imageUrls = ref([])
|
||||||
|
const imageFinding = ref('')
|
||||||
|
const imageDiagnosis = ref('')
|
||||||
|
const examConclusion = ref('')
|
||||||
|
const user = ref(null)
|
||||||
|
const patientDataCache = ref(new Map())
|
||||||
|
const pacsData = ref([])
|
||||||
|
const isImageDepartment = ref(false)
|
||||||
|
|
||||||
|
// 添加检查类型标签
|
||||||
|
const examTabs = ref([
|
||||||
|
{ id: 'ct', name: 'CT检查', color: '#409EFF' },
|
||||||
|
{ id: 'mri', name: 'MRI检查', color: '#67C23A' },
|
||||||
|
{ id: 'xray', name: 'X光检查', color: '#E6A23C' },
|
||||||
|
{ id: 'ultrasound', name: '超声检查', color: '#F56C6C' },
|
||||||
|
{ id: 'ecg', name: '心电图检查', color: '#909399' }
|
||||||
|
])
|
||||||
|
|
||||||
|
// 当前选中的检查类型
|
||||||
|
const currentTab = ref('ct')
|
||||||
|
|
||||||
|
// 切换检查类型
|
||||||
|
const switchTab = async (tabId) => {
|
||||||
|
console.log('切换到检查类型:', tabId)
|
||||||
|
currentTab.value = tabId
|
||||||
|
imageUrls.value = await getImageUrlsByType(tabId)
|
||||||
|
console.log('获取到的图片URLs:', imageUrls.value)
|
||||||
|
}
|
||||||
|
|
||||||
|
// 修改获取影像图片URL的方法
|
||||||
|
const getImageUrlsByType = async (type) => {
|
||||||
|
try {
|
||||||
|
console.log('开始获取PACS数据, 参数:', {
|
||||||
|
code: reportData.value.medicalSn,
|
||||||
|
type: type.toUpperCase(),
|
||||||
|
pageNo: 1,
|
||||||
|
pageSize: 100
|
||||||
|
})
|
||||||
|
|
||||||
|
// 检查必要参数
|
||||||
|
if (!reportData.value.medicalSn) {
|
||||||
|
console.warn('缺少体检编号(medicalSn)')
|
||||||
|
return []
|
||||||
|
}
|
||||||
|
|
||||||
|
// 简化请求参数,只传递必要的字段
|
||||||
|
const response = await PacsDataApi.getPacsDataPage({
|
||||||
|
code: reportData.value.medicalSn,
|
||||||
|
type: type.toUpperCase(),
|
||||||
|
pageNo: 1,
|
||||||
|
pageSize: 100
|
||||||
|
})
|
||||||
|
|
||||||
|
if (!response?.list) {
|
||||||
|
console.warn('PACS数据列表为空')
|
||||||
|
return []
|
||||||
|
}
|
||||||
|
|
||||||
|
pacsData.value = response.list
|
||||||
|
// 直接使用data字段作为图片URL,过滤掉空值
|
||||||
|
const urls = response.list
|
||||||
|
.map(item => item.data)
|
||||||
|
.filter(url => url)
|
||||||
|
|
||||||
|
return urls
|
||||||
|
} catch (error) {
|
||||||
|
console.error('获取PACS数据失败:', error)
|
||||||
|
ElMessage.error('获取影像数据失败,请联系管理员')
|
||||||
|
return []
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// 处理图片加载错误
|
||||||
|
const handleImageError = (e) => {
|
||||||
|
e.target.src = 'https://via.placeholder.com/500x400?text=Image+Not+Found'
|
||||||
|
}
|
||||||
|
|
||||||
|
// 年龄计算属性
|
||||||
|
const age = computed(() => {
|
||||||
|
if (!reportData.value.birthday) return ''
|
||||||
|
|
||||||
|
// 处理 YYYY-MM-DD 格式的生日
|
||||||
|
const birthDate = new Date(reportData.value.birthday)
|
||||||
|
if (isNaN(birthDate.getTime())) return '' // 日期无效时返回空字符串
|
||||||
|
|
||||||
|
const today = new Date()
|
||||||
|
let age = today.getFullYear() - birthDate.getFullYear()
|
||||||
|
const monthDiff = today.getMonth() - birthDate.getMonth()
|
||||||
|
|
||||||
|
// 如果还没到生日月份,或者是生日月但还没到具体日期,年龄减1
|
||||||
|
if (monthDiff < 0 || (monthDiff === 0 && today.getDate() < birthDate.getDate())) {
|
||||||
|
age--
|
||||||
|
}
|
||||||
|
|
||||||
|
return age
|
||||||
|
})
|
||||||
|
|
||||||
|
// 格式化后的检查日期计算属性
|
||||||
|
const formattedMedicalDateTime = computed(() => {
|
||||||
|
if (!reportData.value.medicalDateTime) return ''
|
||||||
|
const date = new Date(reportData.value.medicalDateTime)
|
||||||
|
return date.toLocaleDateString('zh-CN', {
|
||||||
|
year: 'numeric',
|
||||||
|
month: '2-digit',
|
||||||
|
day: '2-digit'
|
||||||
|
}).replace(/\//g, '-')
|
||||||
|
})
|
||||||
|
|
||||||
|
// 是否只读的计算属性
|
||||||
|
const isReadOnly = computed(() => {
|
||||||
|
return props.patient?.status === 1
|
||||||
|
})
|
||||||
|
|
||||||
|
// 检查编辑权限的方法
|
||||||
|
const checkEditPermission = () => {
|
||||||
|
if (isReadOnly.value) {
|
||||||
|
ElMessage.warning('检查结果已保存,不可进行编辑')
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
|
||||||
|
// 保存结果方法
|
||||||
|
const handleSaveResults = async () => {
|
||||||
|
try {
|
||||||
|
const userProfile = await getUserProfile()
|
||||||
|
user.value = userProfile
|
||||||
|
|
||||||
|
// 获取当前时间戳
|
||||||
|
const currentTime = new Date().getTime()
|
||||||
|
|
||||||
|
// 更新检查项目结果
|
||||||
|
const updatedItems = [{
|
||||||
|
id: props.patient.id,
|
||||||
|
examDescription: imageFinding.value,
|
||||||
|
itemResult: imageDiagnosis.value,
|
||||||
|
analyse: examConclusion.value,
|
||||||
|
inspectdoctor: user.value?.nickname || '',
|
||||||
|
itemStatus: '1', // 已检查
|
||||||
|
inspecttime: currentTime
|
||||||
|
}]
|
||||||
|
|
||||||
|
await PatientitemsApi.updatePatientitemsBatch(updatedItems)
|
||||||
|
|
||||||
|
// 更新患者状态为已检查
|
||||||
|
if (props.patient) {
|
||||||
|
const patientData = {
|
||||||
|
...props.patient,
|
||||||
|
status: 1,
|
||||||
|
medicalDateTime: currentTime
|
||||||
|
}
|
||||||
|
await PatientApi.updatePatient(patientData)
|
||||||
|
}
|
||||||
|
|
||||||
|
ElMessage.success('保存成功')
|
||||||
|
|
||||||
|
} catch (error) {
|
||||||
|
console.error('保存失败:', error)
|
||||||
|
ElMessage.error(`保存失败: ${error.message}`)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// 加载患者数据
|
||||||
|
const loadPatientData = async (patient) => {
|
||||||
|
if (!patient || !patient.id) {
|
||||||
|
console.log('没有有效的患者数据')
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
try {
|
||||||
|
console.log('开始加载患者数据:', patient.id)
|
||||||
|
const cacheKey = patient.id
|
||||||
|
if (patientDataCache.value.has(cacheKey)) {
|
||||||
|
console.log('使用缓存的患者数据')
|
||||||
|
const cachedData = patientDataCache.value.get(cacheKey)
|
||||||
|
reportData.value = cachedData.reportData
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
const loading = ElLoading.service({
|
||||||
|
lock: true,
|
||||||
|
text: '加载中...',
|
||||||
|
background: 'rgba(255, 255, 255, 0.7)'
|
||||||
|
})
|
||||||
|
|
||||||
|
try {
|
||||||
|
// 获取用户信息和患者数据
|
||||||
|
const [userProfile, patientData] = await Promise.all([
|
||||||
|
getUserProfile(),
|
||||||
|
PatientApi.getPatient(patient.id)
|
||||||
|
])
|
||||||
|
|
||||||
|
user.value = userProfile
|
||||||
|
reportData.value = patientData
|
||||||
|
|
||||||
|
// 缓存数据
|
||||||
|
patientDataCache.value.set(cacheKey, {
|
||||||
|
reportData: { ...reportData.value }
|
||||||
|
})
|
||||||
|
|
||||||
|
} finally {
|
||||||
|
loading.close()
|
||||||
|
}
|
||||||
|
|
||||||
|
} catch (error) {
|
||||||
|
console.error('获取患者详细信息出错:', error)
|
||||||
|
ElMessage.error('获取患者详细信息失败')
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// 监听患者变化
|
||||||
|
watch(() => props.patient, (newPatient) => {
|
||||||
|
if (newPatient) {
|
||||||
|
loadPatientData(newPatient)
|
||||||
|
}
|
||||||
|
}, { immediate: true })
|
||||||
|
|
||||||
|
// 修改组件挂载时的逻辑
|
||||||
|
onMounted(async () => {
|
||||||
|
if (props.patient) {
|
||||||
|
await loadPatientData(props.patient)
|
||||||
|
// 加载默认tab的影像数据
|
||||||
|
imageUrls.value = await getImageUrlsByType(currentTab.value)
|
||||||
|
}
|
||||||
|
})
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<style scoped>
|
||||||
|
.ct-container {
|
||||||
|
flex: 1;
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
position: relative;
|
||||||
|
background: #fff;
|
||||||
|
height: 100%;
|
||||||
|
padding: 20px;
|
||||||
|
box-shadow: 0 2px 12px 0 rgba(0, 0, 0, 0.1);
|
||||||
|
border-radius: 4px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.basic-info {
|
||||||
|
flex-shrink: 0; /* 防止基本信息被压缩 */
|
||||||
|
display: flex;
|
||||||
|
gap: 20px;
|
||||||
|
padding: 15px; /* 减小内边距 */
|
||||||
|
background: #F8F9FA;
|
||||||
|
border-radius: 4px;
|
||||||
|
margin-bottom: 15px; /* 减小底部间距 */
|
||||||
|
box-shadow: 0 1px 4px rgba(0, 0, 0, 0.05);
|
||||||
|
}
|
||||||
|
|
||||||
|
.photo-box {
|
||||||
|
width: 120px;
|
||||||
|
height: 160px;
|
||||||
|
background: #fff;
|
||||||
|
border: 1px dashed #dcdfe6;
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
justify-content: center;
|
||||||
|
overflow: hidden;
|
||||||
|
}
|
||||||
|
|
||||||
|
.no-photo {
|
||||||
|
color: #909399;
|
||||||
|
font-size: 14px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.photo {
|
||||||
|
width: 100%;
|
||||||
|
height: 100%;
|
||||||
|
object-fit: cover;
|
||||||
|
}
|
||||||
|
|
||||||
|
.info-grid {
|
||||||
|
flex: 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
.info-row {
|
||||||
|
display: flex;
|
||||||
|
margin-bottom: 15px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.info-row:last-child {
|
||||||
|
margin-bottom: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
.info-item {
|
||||||
|
flex: 1;
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
min-width: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
.info-item label {
|
||||||
|
color: #606266;
|
||||||
|
margin-right: 8px;
|
||||||
|
white-space: nowrap;
|
||||||
|
font-weight: 500;
|
||||||
|
}
|
||||||
|
|
||||||
|
.info-item span {
|
||||||
|
color: #333;
|
||||||
|
flex: 1;
|
||||||
|
overflow: hidden;
|
||||||
|
text-overflow: ellipsis;
|
||||||
|
white-space: nowrap;
|
||||||
|
}
|
||||||
|
|
||||||
|
.exam-results {
|
||||||
|
flex: 1;
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
min-height: 0; /* 关键:允许内容收缩 */
|
||||||
|
overflow: hidden; /* 防止溢出 */
|
||||||
|
}
|
||||||
|
|
||||||
|
.exam-tabs {
|
||||||
|
flex-shrink: 0;
|
||||||
|
display: flex;
|
||||||
|
margin-bottom: 15px;
|
||||||
|
position: sticky;
|
||||||
|
top: 0;
|
||||||
|
z-index: 10;
|
||||||
|
background: #fff;
|
||||||
|
padding: 10px 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
.tab-item {
|
||||||
|
position: relative;
|
||||||
|
padding: 8px 16px;
|
||||||
|
margin-right: 10px;
|
||||||
|
cursor: pointer;
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
gap: 8px;
|
||||||
|
border-radius: 4px;
|
||||||
|
background: #fff;
|
||||||
|
color: #606266;
|
||||||
|
font-size: 14px;
|
||||||
|
border: 1px solid #dcdfe6;
|
||||||
|
transition: all 0.3s;
|
||||||
|
z-index: 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
.tab-indicator {
|
||||||
|
width: 12px;
|
||||||
|
height: 12px;
|
||||||
|
border-radius: 2px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.tab-item.active {
|
||||||
|
background: #f5f7fa;
|
||||||
|
border-color: #409EFF;
|
||||||
|
font-weight: 500;
|
||||||
|
transform: translateY(-2px);
|
||||||
|
box-shadow: 0 2px 6px rgba(0, 0, 0, 0.1);
|
||||||
|
}
|
||||||
|
|
||||||
|
.tab-item:hover:not(.active) {
|
||||||
|
border-color: #c0c4cc;
|
||||||
|
background: #f9f9f9;
|
||||||
|
}
|
||||||
|
|
||||||
|
.image-results {
|
||||||
|
flex: 1;
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
min-height: 0; /* 关键:允许内容收缩 */
|
||||||
|
overflow: hidden;
|
||||||
|
}
|
||||||
|
|
||||||
|
.image-gallery {
|
||||||
|
flex: 1;
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
margin-bottom: 20px;
|
||||||
|
border: 1px solid #ebeef5;
|
||||||
|
border-radius: 4px;
|
||||||
|
overflow: hidden;
|
||||||
|
box-shadow: 0 1px 4px rgba(0, 0, 0, 0.05);
|
||||||
|
}
|
||||||
|
|
||||||
|
.gallery-title {
|
||||||
|
padding: 12px 15px;
|
||||||
|
font-weight: 500;
|
||||||
|
background: #f5f7fa;
|
||||||
|
border-bottom: 1px solid #ebeef5;
|
||||||
|
color: #303133;
|
||||||
|
}
|
||||||
|
|
||||||
|
.image-container {
|
||||||
|
flex: 1;
|
||||||
|
padding: 15px;
|
||||||
|
min-height: 0; /* 允许容器收缩 */
|
||||||
|
overflow: auto; /* 如果内容过多,只在图片区域显示滚动条 */
|
||||||
|
}
|
||||||
|
|
||||||
|
.image-grid {
|
||||||
|
display: grid;
|
||||||
|
grid-template-columns: repeat(auto-fill, minmax(400px, 1fr));
|
||||||
|
gap: 20px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.image-item {
|
||||||
|
border: 1px solid #ebeef5;
|
||||||
|
border-radius: 4px;
|
||||||
|
overflow: hidden;
|
||||||
|
transition: transform 0.3s;
|
||||||
|
box-shadow: 0 2px 12px 0 rgba(0, 0, 0, 0.05);
|
||||||
|
aspect-ratio: 4/3;
|
||||||
|
}
|
||||||
|
|
||||||
|
.medical-image {
|
||||||
|
width: 100%;
|
||||||
|
height: 100%;
|
||||||
|
}
|
||||||
|
|
||||||
|
.no-images {
|
||||||
|
display: flex;
|
||||||
|
justify-content: center;
|
||||||
|
align-items: center;
|
||||||
|
height: 300px;
|
||||||
|
color: #909399;
|
||||||
|
}
|
||||||
|
|
||||||
|
.findings-diagnosis-container {
|
||||||
|
flex-shrink: 0; /* 防止诊断区域被压缩 */
|
||||||
|
display: flex;
|
||||||
|
gap: 20px;
|
||||||
|
margin: 15px 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
.findings-section,
|
||||||
|
.diagnosis-section {
|
||||||
|
flex: 1;
|
||||||
|
padding: 15px;
|
||||||
|
background: #f8f9fa;
|
||||||
|
border-radius: 4px;
|
||||||
|
box-shadow: 0 1px 4px rgba(0, 0, 0, 0.05);
|
||||||
|
}
|
||||||
|
|
||||||
|
.section-title {
|
||||||
|
font-size: 16px;
|
||||||
|
font-weight: 500;
|
||||||
|
color: #303133;
|
||||||
|
margin-bottom: 15px;
|
||||||
|
padding-left: 10px;
|
||||||
|
border-left: 4px solid #409eff;
|
||||||
|
}
|
||||||
|
|
||||||
|
.findings-textarea,
|
||||||
|
.diagnosis-textarea {
|
||||||
|
height: 100px; /* 减小文本框高度 */
|
||||||
|
width: 100%;
|
||||||
|
padding: 12px;
|
||||||
|
border: 1px solid #dcdfe6;
|
||||||
|
border-radius: 4px;
|
||||||
|
resize: none;
|
||||||
|
font-size: 14px;
|
||||||
|
line-height: 1.5;
|
||||||
|
background: #fff;
|
||||||
|
transition: border-color 0.3s;
|
||||||
|
margin-bottom: 15px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.findings-textarea:focus,
|
||||||
|
.diagnosis-textarea:focus {
|
||||||
|
outline: none;
|
||||||
|
border-color: #409EFF;
|
||||||
|
box-shadow: 0 0 0 2px rgba(64, 158, 255, 0.2);
|
||||||
|
}
|
||||||
|
|
||||||
|
.findings-textarea[readonly],
|
||||||
|
.diagnosis-textarea[readonly] {
|
||||||
|
background-color: #f5f7fa;
|
||||||
|
cursor: not-allowed;
|
||||||
|
}
|
||||||
|
|
||||||
|
.action-footer {
|
||||||
|
flex-shrink: 0; /* 防止底部操作栏被压缩 */
|
||||||
|
margin-top: 15px;
|
||||||
|
background: #fff;
|
||||||
|
border-top: 1px solid #ebeef5;
|
||||||
|
}
|
||||||
|
|
||||||
|
.footer-content {
|
||||||
|
padding: 15px 20px;
|
||||||
|
display: flex;
|
||||||
|
justify-content: space-between;
|
||||||
|
align-items: center;
|
||||||
|
}
|
||||||
|
|
||||||
|
.doctor-info {
|
||||||
|
display: flex;
|
||||||
|
gap: 20px;
|
||||||
|
color: #606266;
|
||||||
|
font-size: 14px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.action-buttons {
|
||||||
|
display: flex;
|
||||||
|
gap: 15px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.action-btn {
|
||||||
|
padding: 8px 20px;
|
||||||
|
border: none;
|
||||||
|
border-radius: 4px;
|
||||||
|
background: #f0f2f5;
|
||||||
|
color: #606266;
|
||||||
|
cursor: pointer;
|
||||||
|
font-size: 14px;
|
||||||
|
transition: all 0.3s;
|
||||||
|
font-weight: 500;
|
||||||
|
}
|
||||||
|
|
||||||
|
.action-btn:hover {
|
||||||
|
background: #e6e8eb;
|
||||||
|
}
|
||||||
|
|
||||||
|
.action-btn.primary {
|
||||||
|
background: #409EFF;
|
||||||
|
color: white;
|
||||||
|
}
|
||||||
|
|
||||||
|
.action-btn.primary:hover {
|
||||||
|
background: #66b1ff;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* 添加图片错误状态的样式 */
|
||||||
|
.image-error {
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
align-items: center;
|
||||||
|
justify-content: center;
|
||||||
|
height: 100%;
|
||||||
|
background: #f8f9fa;
|
||||||
|
color: #909399;
|
||||||
|
}
|
||||||
|
|
||||||
|
.error-text {
|
||||||
|
margin-top: 8px;
|
||||||
|
font-size: 14px;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* 自定义 el-image 预览样式 */
|
||||||
|
:deep(.el-image-viewer__wrapper) {
|
||||||
|
.el-image-viewer__btn {
|
||||||
|
background-color: rgba(0, 0, 0, 0.3);
|
||||||
|
&:hover {
|
||||||
|
background-color: rgba(0, 0, 0, 0.5);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</style>
|
@ -53,191 +53,203 @@
|
|||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<!-- 右侧检查结果 -->
|
<!-- 右侧检查结果 -->
|
||||||
<div class="report-content" v-if="selectedPatient">
|
<template v-if="selectedPatient">
|
||||||
<!-- 基本信息 -->
|
|
||||||
<div class="basic-info">
|
<!-- 根据科室类型动态显示不同组件 -->
|
||||||
<div class="photo-box">
|
<CT v-if="isImageDepartment" :patient="selectedPatient" />
|
||||||
<img v-if="reportData.headPicUrl" :src="reportData.headPicUrl" alt="头像" class="photo"/>
|
<blood-test
|
||||||
<div v-else class="no-photo">个人照片</div>
|
v-else-if="isBloodTest"
|
||||||
</div>
|
:patient="selectedPatient"
|
||||||
<div class="info-grid">
|
:user="user"
|
||||||
<div class="info-row">
|
/>
|
||||||
<div class="info-item">
|
|
||||||
<label>体检编号:</label>
|
<!-- 常规检查结果界面 -->
|
||||||
<span>{{ reportData.medicalSn }}</span>
|
<div class="report-content" v-else>
|
||||||
</div>
|
<!-- 基本信息 -->
|
||||||
<div class="info-item">
|
<div class="basic-info">
|
||||||
<label>身份证号:</label>
|
<div class="photo-box">
|
||||||
<span>{{ reportData.cardId }}</span>
|
<img v-if="reportData.headPicUrl" :src="reportData.headPicUrl" alt="头像" class="photo"/>
|
||||||
</div>
|
<div v-else class="no-photo">个人照片</div>
|
||||||
<div class="info-item">
|
|
||||||
<label>姓名:</label>
|
|
||||||
<span>{{ reportData.pname }}</span>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
</div>
|
</div>
|
||||||
<div class="info-row">
|
<div class="info-grid">
|
||||||
<div class="info-item">
|
<div class="info-row">
|
||||||
<label>性别:</label>
|
<div class="info-item">
|
||||||
<span>{{ reportData.gender }}</span>
|
<label>体检编号:</label>
|
||||||
|
<span>{{ reportData.medicalSn }}</span>
|
||||||
|
</div>
|
||||||
|
<div class="info-item">
|
||||||
|
<label>身份证号:</label>
|
||||||
|
<span>{{ reportData.cardId }}</span>
|
||||||
|
</div>
|
||||||
|
<div class="info-item">
|
||||||
|
<label>姓名:</label>
|
||||||
|
<span>{{ reportData.pname }}</span>
|
||||||
|
</div>
|
||||||
|
|
||||||
</div>
|
</div>
|
||||||
<div class="info-item">
|
<div class="info-row">
|
||||||
<label>年龄:</label>
|
<div class="info-item">
|
||||||
<span>{{ age }}岁</span>
|
<label>性别:</label>
|
||||||
</div>
|
<span>{{ reportData.gender }}</span>
|
||||||
<div class="info-item">
|
</div>
|
||||||
<label>电话:</label>
|
<div class="info-item">
|
||||||
<span>{{ reportData.phoneNum }}</span>
|
<label>年龄:</label>
|
||||||
|
<span>{{ age }}岁</span>
|
||||||
|
</div>
|
||||||
|
<div class="info-item">
|
||||||
|
<label>电话:</label>
|
||||||
|
<span>{{ reportData.phoneNum }}</span>
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
|
||||||
|
|
||||||
<!-- 检查结果部分 -->
|
<!-- 检查结果部分 -->
|
||||||
<div class="exam-results">
|
<div class="exam-results">
|
||||||
<!-- 检查项目标签 -->
|
<!-- 检查项目标签 -->
|
||||||
<div class="exam-tabs">
|
<div class="exam-tabs">
|
||||||
<div
|
|
||||||
v-for="tab in examTabs"
|
|
||||||
:key="tab.id"
|
|
||||||
:class="['tab-item', { active: currentTab === tab.id }]"
|
|
||||||
@click="switchTab(tab.id)"
|
|
||||||
>
|
|
||||||
<div class="tab-indicator" :style="{ background: tab.color }"></div>
|
|
||||||
<span>{{ tab.name }}</span>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<!-- 检查结果表格 -->
|
|
||||||
<div class="result-table">
|
|
||||||
<!-- 表头部分 -->
|
|
||||||
<div class="table-header">
|
|
||||||
<div class="header-row">
|
|
||||||
<div class="header-cell" style="width: 5%">#</div>
|
|
||||||
<div class="header-cell" style="width: 15%">体检项目</div>
|
|
||||||
<div class="header-cell" style="width: 20%">明细结果</div>
|
|
||||||
<div class="header-cell" style="width: 10%">单位</div>
|
|
||||||
<div class="header-cell" style="width: 15%">参考值</div>
|
|
||||||
<div class="header-cell" style="width: 10%">提示</div>
|
|
||||||
<div class="header-cell" style="width: 15%">危险程度</div>
|
|
||||||
<div class="header-cell" style="width: 10%">是否阳性</div>
|
|
||||||
<div class="header-cell" style="width: 10%">操作</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<!-- 表格内容部分 -->
|
|
||||||
<div class="table-body">
|
|
||||||
<div
|
<div
|
||||||
v-for="(item, index) in sortedExamItems"
|
v-for="tab in examTabs"
|
||||||
:key="item.id"
|
:key="tab.id"
|
||||||
class="table-row"
|
:class="['tab-item', { active: currentTab === tab.id }]"
|
||||||
:class="{
|
@click="switchTab(tab.id)"
|
||||||
'warning-row': item.status === 'warning',
|
|
||||||
'danger-row': item.status === 'danger'
|
|
||||||
}"
|
|
||||||
:data-item-status="item.itemStatus"
|
|
||||||
>
|
>
|
||||||
<div class="table-cell" style="width: 5%">{{ index + 1 }}</div>
|
<div class="tab-indicator" :style="{ background: tab.color }"></div>
|
||||||
<div class="table-cell" style="width: 15%">{{ item.name }}</div>
|
<span>{{ tab.name }}</span>
|
||||||
<div class="table-cell" style="width: 20%">
|
</div>
|
||||||
<input
|
</div>
|
||||||
type="text"
|
|
||||||
v-model="item.value"
|
<!-- 检查结果表格 -->
|
||||||
@change="handleResultChange(item)"
|
<div class="result-table">
|
||||||
@click="checkEditPermission"
|
<!-- 表头部分 -->
|
||||||
class="cell-input"
|
<div class="table-header">
|
||||||
:readonly="isReadOnly"
|
<div class="header-row">
|
||||||
/>
|
<div class="header-cell" style="width: 5%">#</div>
|
||||||
|
<div class="header-cell" style="width: 15%">体检项目</div>
|
||||||
|
<div class="header-cell" style="width: 20%">明细结果</div>
|
||||||
|
<div class="header-cell" style="width: 10%">单位</div>
|
||||||
|
<div class="header-cell" style="width: 15%">参考值</div>
|
||||||
|
<div class="header-cell" style="width: 10%">提示</div>
|
||||||
|
<div class="header-cell" style="width: 15%">危险程度</div>
|
||||||
|
<div class="header-cell" style="width: 10%">是否阳性</div>
|
||||||
|
<div class="header-cell" style="width: 10%">操作</div>
|
||||||
</div>
|
</div>
|
||||||
<div class="table-cell" style="width: 10%">{{ item.unit }}</div>
|
</div>
|
||||||
<div class="table-cell" style="width: 15%">
|
|
||||||
{{ formatReference(item.reference) }}
|
<!-- 表格内容部分 -->
|
||||||
</div>
|
<div class="table-body">
|
||||||
<div class="table-cell" style="width: 10%">{{ item.note }}</div>
|
<div
|
||||||
<div class="table-cell" style="width: 15%">{{ item.risk }}</div>
|
v-for="(item, index) in sortedExamItems"
|
||||||
<div class="table-cell" style="width: 10%">
|
:key="item.id"
|
||||||
<el-tag
|
class="table-row"
|
||||||
v-if="item.positive === '阳性'"
|
:class="{
|
||||||
type="danger"
|
'warning-row': item.status === 'warning',
|
||||||
size="small"
|
'danger-row': item.status === 'danger'
|
||||||
effect="light"
|
}"
|
||||||
class="positive-indicator"
|
:data-item-status="item.itemStatus"
|
||||||
>
|
>
|
||||||
阳性
|
<div class="table-cell" style="width: 5%">{{ index + 1 }}</div>
|
||||||
</el-tag>
|
<div class="table-cell" style="width: 15%">{{ item.name }}</div>
|
||||||
<span v-else class="negative-text">阴性</span>
|
<div class="table-cell" style="width: 20%">
|
||||||
</div>
|
<input
|
||||||
<div class="table-cell" style="width: 10%">
|
type="text"
|
||||||
<el-dropdown @command="handleOperation">
|
v-model="item.value"
|
||||||
<el-button size="small" :class="{ 'view-only': isReadOnly }">
|
@change="handleResultChange(item)"
|
||||||
更多操作
|
@click="checkEditPermission"
|
||||||
<el-icon class="el-icon--right"><arrow-down /></el-icon>
|
class="cell-input"
|
||||||
</el-button>
|
:readonly="isReadOnly"
|
||||||
<template #dropdown>
|
/>
|
||||||
<el-dropdown-menu>
|
</div>
|
||||||
<el-dropdown-item
|
<div class="table-cell" style="width: 10%">{{ item.unit }}</div>
|
||||||
:command="{ type: 'positive', item: item }"
|
<div class="table-cell" style="width: 15%">
|
||||||
:class="{ 'is-active': item.positive === '阳性' }"
|
{{ formatReference(item.reference) }}
|
||||||
>
|
</div>
|
||||||
阳性
|
<div class="table-cell" style="width: 10%">{{ item.note }}</div>
|
||||||
</el-dropdown-item>
|
<div class="table-cell" style="width: 15%">{{ item.risk }}</div>
|
||||||
<el-dropdown-item
|
<div class="table-cell" style="width: 10%">
|
||||||
:command="{ type: 'negative', item: item }"
|
<el-tag
|
||||||
:class="{ 'is-active': item.positive === '阴性' }"
|
v-if="item.positive === '阳性'"
|
||||||
>
|
type="danger"
|
||||||
阴性
|
size="small"
|
||||||
</el-dropdown-item>
|
effect="light"
|
||||||
<el-dropdown-item
|
class="positive-indicator"
|
||||||
divided
|
>
|
||||||
:command="{ type: 'abandon', item: item }"
|
阳性
|
||||||
:class="{ 'is-danger': item.itemStatus !== '2' }"
|
</el-tag>
|
||||||
style="color: red;"
|
<span v-else class="negative-text">阴性</span>
|
||||||
>
|
</div>
|
||||||
{{ item.itemStatus === '2' ? '恢复正常' : '弃检' }}
|
<div class="table-cell" style="width: 10%">
|
||||||
</el-dropdown-item>
|
<el-dropdown @command="handleOperation">
|
||||||
</el-dropdown-menu>
|
<el-button size="small" :class="{ 'view-only': isReadOnly }">
|
||||||
</template>
|
更多操作
|
||||||
</el-dropdown>
|
<el-icon class="el-icon--right"><arrow-down /></el-icon>
|
||||||
|
</el-button>
|
||||||
|
<template #dropdown>
|
||||||
|
<el-dropdown-menu>
|
||||||
|
<el-dropdown-item
|
||||||
|
:command="{ type: 'positive', item: item }"
|
||||||
|
:class="{ 'is-active': item.positive === '阳性' }"
|
||||||
|
>
|
||||||
|
阳性
|
||||||
|
</el-dropdown-item>
|
||||||
|
<el-dropdown-item
|
||||||
|
:command="{ type: 'negative', item: item }"
|
||||||
|
:class="{ 'is-active': item.positive === '阴性' }"
|
||||||
|
>
|
||||||
|
阴性
|
||||||
|
</el-dropdown-item>
|
||||||
|
<el-dropdown-item
|
||||||
|
divided
|
||||||
|
:command="{ type: 'abandon', item: item }"
|
||||||
|
:class="{ 'is-danger': item.itemStatus !== '2' }"
|
||||||
|
style="color: red;"
|
||||||
|
>
|
||||||
|
{{ item.itemStatus === '2' ? '恢复正常' : '弃检' }}
|
||||||
|
</el-dropdown-item>
|
||||||
|
</el-dropdown-menu>
|
||||||
|
</template>
|
||||||
|
</el-dropdown>
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
<!-- 将体检小结移到这里,与表格同级 -->
|
||||||
|
<div class="summary-section">
|
||||||
|
<div class="section-title">体检小结</div>
|
||||||
|
<textarea
|
||||||
|
v-model="examConclusion"
|
||||||
|
placeholder="输入多个以分号隔开"
|
||||||
|
class="summary-textarea"
|
||||||
|
:readonly="isReadOnly"
|
||||||
|
></textarea>
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<!-- 将体检小结移到这里,与表格同级 -->
|
<!-- 底部操作栏 -->
|
||||||
<div class="summary-section">
|
<div class="action-footer">
|
||||||
<div class="section-title">体检小结</div>
|
<div class="left-section">
|
||||||
<textarea
|
<span>检查医生:</span>
|
||||||
v-model="examConclusion"
|
<span>{{ user?.nickname || '暂无' }}</span>
|
||||||
placeholder="输入多个以分号隔开"
|
<span style="margin-left: 100px;">检查日期:{{ formattedMedicalDateTime }}</span>
|
||||||
class="summary-textarea"
|
</div>
|
||||||
:readonly="isReadOnly"
|
<div class="right-section">
|
||||||
></textarea>
|
<div class="action-buttons">
|
||||||
</div>
|
<button class="action-btn" @click="checkEditPermission">同步结果</button>
|
||||||
</div>
|
<button class="action-btn">报告预览</button>
|
||||||
|
<button class="action-btn" @click="checkEditPermission">弃检</button>
|
||||||
<!-- 底部操作栏 -->
|
<button
|
||||||
<div class="action-footer">
|
v-if="!isReadOnly"
|
||||||
<div class="left-section">
|
class="action-btn primary"
|
||||||
<span>检查医生:</span>
|
@click="handleSaveResults"
|
||||||
<span>{{ user?.nickname || '暂无' }}</span>
|
>
|
||||||
<span style="margin-left: 100px;">检查日期:{{ formattedMedicalDateTime }}</span>
|
保存结果
|
||||||
</div>
|
</button>
|
||||||
<div class="right-section">
|
</div>
|
||||||
<div class="action-buttons">
|
|
||||||
<button class="action-btn" @click="checkEditPermission">同步结果</button>
|
|
||||||
<button class="action-btn">报告预览</button>
|
|
||||||
<button class="action-btn" @click="checkEditPermission">弃检</button>
|
|
||||||
<button
|
|
||||||
v-if="!isReadOnly"
|
|
||||||
class="action-btn primary"
|
|
||||||
@click="handleSaveResults"
|
|
||||||
>
|
|
||||||
保存结果
|
|
||||||
</button>
|
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</template>
|
||||||
|
|
||||||
<!-- 添加未选择患者时的提示 -->
|
<!-- 添加未选择患者时的提示 -->
|
||||||
<div class="empty-content" v-else>
|
<div class="empty-content" v-else>
|
||||||
@ -281,7 +293,9 @@ import { PatientApi } from '@/api/inspect/inspectpatient'
|
|||||||
import { PatientitemsApi } from '@/api/inspect/inspectpatientitems'
|
import { PatientitemsApi } from '@/api/inspect/inspectpatientitems'
|
||||||
import { getUserProfile } from '@/api/system/user/profile'
|
import { getUserProfile } from '@/api/system/user/profile'
|
||||||
import ExamImages from './Exam_images.vue'
|
import ExamImages from './Exam_images.vue'
|
||||||
|
import CT from './CT.vue' // 导入CT组件
|
||||||
import { ArrowDown } from '@element-plus/icons-vue'
|
import { ArrowDown } from '@element-plus/icons-vue'
|
||||||
|
import BloodTest from './blood.vue' // 导入血常规组件
|
||||||
|
|
||||||
const dialogTitle = ref('体检报告')
|
const dialogTitle = ref('体检报告')
|
||||||
const { t } = useI18n() // 国际化
|
const { t } = useI18n() // 国际化
|
||||||
@ -456,7 +470,6 @@ const getpatientitemData = async (medicalSn) => {
|
|||||||
try {
|
try {
|
||||||
const userProfile = await getUserProfile()
|
const userProfile = await getUserProfile()
|
||||||
user.value = userProfile
|
user.value = userProfile
|
||||||
console.log('当前登录用户信息:', userProfile)
|
|
||||||
} catch (userError) {
|
} catch (userError) {
|
||||||
console.error('获取用户信息失败:', userError)
|
console.error('获取用户信息失败:', userError)
|
||||||
}
|
}
|
||||||
@ -500,48 +513,53 @@ const loadPatientData = async (patient) => {
|
|||||||
])
|
])
|
||||||
|
|
||||||
user.value = userProfile
|
user.value = userProfile
|
||||||
const userDeptId = userProfile // 获取用户部门ID
|
|
||||||
|
// 检查用户是否属于影像科或血常规科室
|
||||||
|
isImageDepartment.value = checkIsImageDepartment(userProfile.deptId)
|
||||||
|
|
||||||
reportData.value = patientData
|
reportData.value = patientData
|
||||||
|
|
||||||
if (itemsRes.list && itemsRes.list.length > 0) {
|
// 如果不是特殊科室,继续加载常规检查数据
|
||||||
examConclusion.value = itemsRes.list[0].analyse || ''
|
if (!isImageDepartment.value && !isBloodTest.value) {
|
||||||
|
if (itemsRes.list && itemsRes.list.length > 0) {
|
||||||
const itemsBySection = {}
|
examConclusion.value = itemsRes.list[0].analyse || ''
|
||||||
// 筛选属于当前用户部门的项目
|
|
||||||
const filteredItems = itemsRes.list.filter(item => item.sectionID == userProfile.deptId)
|
|
||||||
console.log('当前登录用户信息:',filteredItems )
|
|
||||||
filteredItems.forEach(item => {
|
|
||||||
const sectionType = '一般检查'
|
|
||||||
if (!itemsBySection[sectionType]) {
|
|
||||||
itemsBySection[sectionType] = []
|
|
||||||
}
|
|
||||||
|
|
||||||
const processedItem = {
|
const itemsBySection = {}
|
||||||
id: item.id,
|
// 筛选属于当前用户部门的项目
|
||||||
name: item.itemName,
|
const filteredItems = itemsRes.list.filter(item => item.sectionID == userProfile.deptId)
|
||||||
value: item.itemResult,
|
filteredItems.forEach(item => {
|
||||||
unit: item.unit,
|
const sectionType = '一般检查'
|
||||||
reference: `${item.lowValue}-${item.highValue}`,
|
if (!itemsBySection[sectionType]) {
|
||||||
note: getStatusNote(item),
|
itemsBySection[sectionType] = []
|
||||||
risk: getRiskLevel(item),
|
}
|
||||||
status: getRowStatus(item),
|
|
||||||
positive: item.positive === '1' ? '阳性' : '阴性',
|
const processedItem = {
|
||||||
itemStatus: item.itemStatus
|
id: item.id,
|
||||||
}
|
name: item.itemName,
|
||||||
|
value: item.itemResult,
|
||||||
|
unit: item.unit,
|
||||||
|
reference: `${item.lowValue}-${item.highValue}`,
|
||||||
|
note: getStatusNote(item),
|
||||||
|
risk: getRiskLevel(item),
|
||||||
|
status: getRowStatus(item),
|
||||||
|
positive: item.positive === '1' ? '阳性' : '阴性',
|
||||||
|
itemStatus: item.itemStatus
|
||||||
|
}
|
||||||
|
|
||||||
|
itemsBySection[sectionType].push(processedItem)
|
||||||
|
})
|
||||||
|
|
||||||
itemsBySection[sectionType].push(processedItem)
|
examTabs.value = Object.keys(itemsBySection).map((sectionType, index) => ({
|
||||||
})
|
id: sectionType,
|
||||||
|
name: sectionType,
|
||||||
examTabs.value = Object.keys(itemsBySection).map((sectionType, index) => ({
|
color: getTabColor(index)
|
||||||
id: sectionType,
|
}))
|
||||||
name: sectionType,
|
|
||||||
color: getTabColor(index)
|
examItems.value = itemsBySection
|
||||||
}))
|
|
||||||
|
if (examTabs.value.length > 0) {
|
||||||
examItems.value = itemsBySection
|
currentTab.value = examTabs.value[0].id
|
||||||
|
}
|
||||||
if (examTabs.value.length > 0) {
|
|
||||||
currentTab.value = examTabs.value[0].id
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -562,6 +580,23 @@ const loadPatientData = async (patient) => {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// 修改检查是否为影像科的函数
|
||||||
|
const checkIsImageDepartment = (deptId) => {
|
||||||
|
|
||||||
|
// 强制返回true用于测试
|
||||||
|
// return true;
|
||||||
|
|
||||||
|
// 如果deptId是对象,尝试获取其id属性
|
||||||
|
const id = typeof deptId === 'object' ? deptId.id || deptId.deptId : deptId
|
||||||
|
|
||||||
|
// 影像科的ID列表 - 根据实际情况调整
|
||||||
|
const imageDeptIds = ['7', '8', '9', '10', '11', '12', '13', 'CT室', 'DR室', '超声科', '放射科', '影像科', 'CT', 'MRI', '超声', '放射']
|
||||||
|
|
||||||
|
// 检查ID是否在列表中
|
||||||
|
const result = imageDeptIds.includes(String(id))
|
||||||
|
return result
|
||||||
|
}
|
||||||
|
|
||||||
// 修改获取状态提示的函数
|
// 修改获取状态提示的函数
|
||||||
const getStatusNote = (item) => {
|
const getStatusNote = (item) => {
|
||||||
if (!item.reference || item.reference === 'null-null') {
|
if (!item.reference || item.reference === 'null-null') {
|
||||||
@ -673,10 +708,12 @@ const handlePatientSelect = async (patient) => {
|
|||||||
} catch (error) {
|
} catch (error) {
|
||||||
console.error('切换患者失败:', error)
|
console.error('切换患者失败:', error)
|
||||||
message.error('切换患者失败')
|
message.error('切换患者失败')
|
||||||
|
// 出错时重置状态
|
||||||
|
isImageDepartment.value = false
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
onMounted(() => {
|
onMounted(async () => {
|
||||||
// 清理页面状态
|
// 清理页面状态
|
||||||
patients.value = []
|
patients.value = []
|
||||||
selectedPatient.value = null
|
selectedPatient.value = null
|
||||||
@ -720,6 +757,16 @@ onMounted(() => {
|
|||||||
inspecttime: ''
|
inspecttime: ''
|
||||||
}
|
}
|
||||||
customDateRange.value = []
|
customDateRange.value = []
|
||||||
|
|
||||||
|
// 初始化科室类型
|
||||||
|
try {
|
||||||
|
const userProfile = await getUserProfile()
|
||||||
|
user.value = userProfile
|
||||||
|
isImageDepartment.value = checkIsImageDepartment(userProfile.deptId)
|
||||||
|
} catch (error) {
|
||||||
|
console.error('获取用户信息失败:', error)
|
||||||
|
isImageDepartment.value = false
|
||||||
|
}
|
||||||
})
|
})
|
||||||
|
|
||||||
// 当前选中的时间周期
|
// 当前选中的时间周期
|
||||||
@ -928,7 +975,6 @@ const user = ref(null)
|
|||||||
// 加载数据
|
// 加载数据
|
||||||
const loadData = async () => {
|
const loadData = async () => {
|
||||||
reportData.value = await PatientApi.getPatient(1)
|
reportData.value = await PatientApi.getPatient(1)
|
||||||
console.log(reportData.value.birthday)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// 添加搜索处理函数
|
// 添加搜索处理函数
|
||||||
@ -1190,6 +1236,30 @@ const formatReference = (reference) => {
|
|||||||
return `${low}-${high}`
|
return `${low}-${high}`
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// 添加isImageDepartment的响应式引用
|
||||||
|
const isImageDepartment = ref(false)
|
||||||
|
|
||||||
|
// 添加判断是否为血常规检查的计算属性
|
||||||
|
const isBloodTest = computed(() => {
|
||||||
|
if (!selectedPatient.value) return false
|
||||||
|
|
||||||
|
// 获取当前用户部门下的检查项目
|
||||||
|
const currentItems = Object.values(examItems.value)
|
||||||
|
.flat()
|
||||||
|
.filter(item => {
|
||||||
|
// 检查项目名称中包含血常规相关关键词
|
||||||
|
const itemName = (item.name || '').toLowerCase()
|
||||||
|
return itemName.includes('血常规') ||
|
||||||
|
itemName.includes('血细胞') ||
|
||||||
|
itemName.includes('血红蛋白') ||
|
||||||
|
itemName.includes('白细胞') ||
|
||||||
|
itemName.includes('红细胞') ||
|
||||||
|
itemName.includes('血小板')
|
||||||
|
})
|
||||||
|
|
||||||
|
return currentItems.length > 0
|
||||||
|
})
|
||||||
|
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<style scoped>
|
<style scoped>
|
||||||
@ -1866,7 +1936,6 @@ const formatReference = (reference) => {
|
|||||||
background-color: #f5f7fa;
|
background-color: #f5f7fa;
|
||||||
cursor: not-allowed;
|
cursor: not-allowed;
|
||||||
color: #606266;
|
color: #606266;
|
||||||
border: none;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/* 修改弃检行的样式判断 */
|
/* 修改弃检行的样式判断 */
|
||||||
|
284
src/views/Department-entry/blood.vue
Normal file
284
src/views/Department-entry/blood.vue
Normal file
@ -0,0 +1,284 @@
|
|||||||
|
<template>
|
||||||
|
<div class="blood-test-container">
|
||||||
|
<!-- 检查结果表格 -->
|
||||||
|
<div class="result-table">
|
||||||
|
<!-- 表头部分 -->
|
||||||
|
<div class="table-header">
|
||||||
|
<div class="header-row">
|
||||||
|
<div class="header-cell" style="width: 5%">#</div>
|
||||||
|
<div class="header-cell" style="width: 15%">体检项目</div>
|
||||||
|
<div class="header-cell" style="width: 20%">明细结果</div>
|
||||||
|
<div class="header-cell" style="width: 10%">单位</div>
|
||||||
|
<div class="header-cell" style="width: 15%">参考值</div>
|
||||||
|
<div class="header-cell" style="width: 10%">提示</div>
|
||||||
|
<div class="header-cell" style="width: 15%">危险程度</div>
|
||||||
|
<div class="header-cell" style="width: 10%">是否阳性</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<!-- 表格内容部分 -->
|
||||||
|
<div class="table-body">
|
||||||
|
<div
|
||||||
|
v-for="(item, index) in bloodTestItems"
|
||||||
|
:key="item.id"
|
||||||
|
class="table-row"
|
||||||
|
:class="{
|
||||||
|
'warning-row': item.status === 'warning',
|
||||||
|
'danger-row': item.status === 'danger'
|
||||||
|
}"
|
||||||
|
>
|
||||||
|
<div class="table-cell" style="width: 5%">{{ index + 1 }}</div>
|
||||||
|
<div class="table-cell" style="width: 15%">{{ item.name }}</div>
|
||||||
|
<div class="table-cell" style="width: 20%">{{ item.value }}</div>
|
||||||
|
<div class="table-cell" style="width: 10%">{{ item.unit }}</div>
|
||||||
|
<div class="table-cell" style="width: 15%">{{ formatReference(item.reference) }}</div>
|
||||||
|
<div class="table-cell" style="width: 10%">{{ item.note }}</div>
|
||||||
|
<div class="table-cell" style="width: 15%">{{ item.risk }}</div>
|
||||||
|
<div class="table-cell" style="width: 10%">
|
||||||
|
<el-tag
|
||||||
|
v-if="item.positive === '阳性'"
|
||||||
|
type="danger"
|
||||||
|
size="small"
|
||||||
|
effect="light"
|
||||||
|
>
|
||||||
|
阳性
|
||||||
|
</el-tag>
|
||||||
|
<span v-else>阴性</span>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<!-- 底部操作栏 -->
|
||||||
|
<div class="action-footer">
|
||||||
|
<div class="left-section">
|
||||||
|
<span>检查医生:{{ user?.nickname || '暂无' }}</span>
|
||||||
|
<span style="margin-left: 100px;">检查日期:{{ formattedMedicalDateTime }}</span>
|
||||||
|
</div>
|
||||||
|
<div class="right-section">
|
||||||
|
<div class="action-buttons">
|
||||||
|
<button class="action-btn" @click="handleSyncResults">同步结果</button>
|
||||||
|
<button class="action-btn">报告预览</button>
|
||||||
|
<button
|
||||||
|
class="action-btn primary"
|
||||||
|
@click="handleSaveResults"
|
||||||
|
>
|
||||||
|
保存结果
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script>
|
||||||
|
import { ref, computed } from 'vue'
|
||||||
|
import { ElMessage } from 'element-plus'
|
||||||
|
import { PatientitemsApi } from '@/api/inspect/inspectpatientitems'
|
||||||
|
|
||||||
|
export default {
|
||||||
|
name: 'BloodTest',
|
||||||
|
props: {
|
||||||
|
patient: {
|
||||||
|
type: Object,
|
||||||
|
required: true
|
||||||
|
},
|
||||||
|
user: {
|
||||||
|
type: Object,
|
||||||
|
required: true
|
||||||
|
}
|
||||||
|
},
|
||||||
|
setup(props) {
|
||||||
|
const bloodTestItems = ref([])
|
||||||
|
const formattedMedicalDateTime = computed(() => {
|
||||||
|
return new Date().toLocaleDateString('zh-CN')
|
||||||
|
})
|
||||||
|
|
||||||
|
// 格式化参考值显示
|
||||||
|
const formatReference = (reference) => {
|
||||||
|
if (!reference || reference === 'null-null') return '-'
|
||||||
|
const [low, high] = reference.split('-')
|
||||||
|
if (!low || !high || low === 'null' || high === 'null') return '-'
|
||||||
|
return `${low}-${high}`
|
||||||
|
}
|
||||||
|
|
||||||
|
// 同步结果处理函数
|
||||||
|
const handleSyncResults = async () => {
|
||||||
|
try {
|
||||||
|
const params = {
|
||||||
|
medicalSn: props.patient.medicalSn,
|
||||||
|
pageNo: 1,
|
||||||
|
pageSize: 100
|
||||||
|
}
|
||||||
|
const res = await PatientitemsApi.getPatientitemsPage(params)
|
||||||
|
if (res.list && res.list.length > 0) {
|
||||||
|
bloodTestItems.value = res.list.map(item => ({
|
||||||
|
id: item.id,
|
||||||
|
name: item.itemName,
|
||||||
|
value: item.itemResult,
|
||||||
|
unit: item.unit,
|
||||||
|
reference: `${item.lowValue}-${item.highValue}`,
|
||||||
|
note: getStatusNote(item),
|
||||||
|
risk: getRiskLevel(item),
|
||||||
|
status: getRowStatus(item),
|
||||||
|
positive: item.positive === '1' ? '阳性' : '阴性'
|
||||||
|
}))
|
||||||
|
ElMessage.success('同步结果成功')
|
||||||
|
}
|
||||||
|
} catch (error) {
|
||||||
|
console.error('同步结果失败:', error)
|
||||||
|
ElMessage.error('同步结果失败')
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// 保存结果处理函数
|
||||||
|
const handleSaveResults = async () => {
|
||||||
|
try {
|
||||||
|
const updatedItems = bloodTestItems.value.map(item => ({
|
||||||
|
id: item.id,
|
||||||
|
itemResult: item.value,
|
||||||
|
positive: item.positive === '阳性' ? '1' : '0',
|
||||||
|
inspectdoctor: props.user?.nickname || '',
|
||||||
|
inspecttime: new Date().getTime()
|
||||||
|
}))
|
||||||
|
|
||||||
|
await PatientitemsApi.updatePatientitemsBatch(updatedItems)
|
||||||
|
ElMessage.success('保存成功')
|
||||||
|
} catch (error) {
|
||||||
|
console.error('保存失败:', error)
|
||||||
|
ElMessage.error('保存失败')
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// 辅助函数
|
||||||
|
const getStatusNote = (item) => {
|
||||||
|
if (!item.itemResult || !item.lowValue || !item.highValue) return ''
|
||||||
|
const value = parseFloat(item.itemResult)
|
||||||
|
const low = parseFloat(item.lowValue)
|
||||||
|
const high = parseFloat(item.highValue)
|
||||||
|
|
||||||
|
if (value < low) return '↓'
|
||||||
|
if (value > high) return '↑'
|
||||||
|
return '-'
|
||||||
|
}
|
||||||
|
|
||||||
|
const getRiskLevel = (item) => {
|
||||||
|
if (!item.itemResult || !item.lowValue || !item.highValue) return ''
|
||||||
|
const value = parseFloat(item.itemResult)
|
||||||
|
const low = parseFloat(item.lowValue)
|
||||||
|
const high = parseFloat(item.highValue)
|
||||||
|
|
||||||
|
if (value < low) return '低于正常值'
|
||||||
|
if (value > high) return '高于正常值'
|
||||||
|
return '正常'
|
||||||
|
}
|
||||||
|
|
||||||
|
const getRowStatus = (item) => {
|
||||||
|
if (!item.itemResult || !item.lowValue || !item.highValue) return ''
|
||||||
|
const value = parseFloat(item.itemResult)
|
||||||
|
const high = parseFloat(item.highValue)
|
||||||
|
|
||||||
|
if (value > high) return 'danger'
|
||||||
|
return ''
|
||||||
|
}
|
||||||
|
|
||||||
|
return {
|
||||||
|
bloodTestItems,
|
||||||
|
formattedMedicalDateTime,
|
||||||
|
formatReference,
|
||||||
|
handleSyncResults,
|
||||||
|
handleSaveResults
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<style scoped>
|
||||||
|
.blood-test-container {
|
||||||
|
flex: 1;
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
position: relative;
|
||||||
|
background: #fff;
|
||||||
|
height: 100%;
|
||||||
|
}
|
||||||
|
|
||||||
|
.result-table {
|
||||||
|
margin: 20px;
|
||||||
|
border: 1px solid #ebeef5;
|
||||||
|
border-radius: 4px;
|
||||||
|
flex: 1;
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
}
|
||||||
|
|
||||||
|
.table-header {
|
||||||
|
background: #f5f7fa;
|
||||||
|
border-bottom: 1px solid #ebeef5;
|
||||||
|
}
|
||||||
|
|
||||||
|
.header-row {
|
||||||
|
display: flex;
|
||||||
|
width: 100%;
|
||||||
|
}
|
||||||
|
|
||||||
|
.header-cell {
|
||||||
|
padding: 12px 8px;
|
||||||
|
font-weight: 500;
|
||||||
|
color: #606266;
|
||||||
|
text-align: left;
|
||||||
|
border-right: 1px solid #ebeef5;
|
||||||
|
}
|
||||||
|
|
||||||
|
.table-body {
|
||||||
|
flex: 1;
|
||||||
|
overflow-y: auto;
|
||||||
|
}
|
||||||
|
|
||||||
|
.table-row {
|
||||||
|
display: flex;
|
||||||
|
border-bottom: 1px solid #ebeef5;
|
||||||
|
}
|
||||||
|
|
||||||
|
.table-row.danger-row {
|
||||||
|
background: #fef0f0;
|
||||||
|
}
|
||||||
|
|
||||||
|
.table-cell {
|
||||||
|
padding: 12px 8px;
|
||||||
|
border-right: 1px solid #ebeef5;
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
}
|
||||||
|
|
||||||
|
.action-footer {
|
||||||
|
padding: 16px 20px;
|
||||||
|
border-top: 1px solid #ebeef5;
|
||||||
|
display: flex;
|
||||||
|
justify-content: space-between;
|
||||||
|
align-items: center;
|
||||||
|
}
|
||||||
|
|
||||||
|
.action-buttons {
|
||||||
|
display: flex;
|
||||||
|
gap: 12px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.action-btn {
|
||||||
|
padding: 8px 16px;
|
||||||
|
border: none;
|
||||||
|
border-radius: 4px;
|
||||||
|
background: #409EFF;
|
||||||
|
color: white;
|
||||||
|
cursor: pointer;
|
||||||
|
font-size: 14px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.action-btn:hover {
|
||||||
|
opacity: 0.9;
|
||||||
|
}
|
||||||
|
|
||||||
|
.action-btn.primary {
|
||||||
|
background: #67C23A;
|
||||||
|
}
|
||||||
|
</style>
|
@ -1005,20 +1005,43 @@ const handlePersonInfoSave = async () => {
|
|||||||
if (result) {
|
if (result) {
|
||||||
// 保存患者项目
|
// 保存患者项目
|
||||||
if (comboInfoTable1.value.length > 0) {
|
if (comboInfoTable1.value.length > 0) {
|
||||||
const saveItems: PatientitemsVO[] = comboInfoTable1.value.map(item => ({
|
// 先获取患者现有的项目列表
|
||||||
|
const existingItems = await PatientitemsApi.getPatientitemsPage({
|
||||||
medicalSn: personParam.value.testNum,
|
medicalSn: personParam.value.testNum,
|
||||||
itemName: item.name,
|
pageNo: 1,
|
||||||
itemCode: item.itemCode,
|
pageSize: 100
|
||||||
price: item.price,
|
})
|
||||||
discountedPrice: item.discountPrice,
|
|
||||||
discounted: item.discount,
|
|
||||||
sectionID: item.sectionID,
|
|
||||||
itemStatus: '0',
|
|
||||||
createTime: new Date().getTime(), // 修改为时间戳
|
|
||||||
headimage: avatar
|
|
||||||
}))
|
|
||||||
|
|
||||||
await PatientitemsApi.createPatientitemsBatch(saveItems)
|
// 创建现有项目的itemCode集合,用于快速查找
|
||||||
|
const existingItemCodes = new Set(
|
||||||
|
existingItems?.list?.map(item => item.itemCode) || []
|
||||||
|
)
|
||||||
|
|
||||||
|
// 过滤出需要新增的项目(不在现有项目中的)
|
||||||
|
const newItems = comboInfoTable1.value.filter(
|
||||||
|
item => !existingItemCodes.has(item.itemCode)
|
||||||
|
)
|
||||||
|
|
||||||
|
if (newItems.length > 0) {
|
||||||
|
// 直接使用项目中已有的字段值,不使用默认值
|
||||||
|
const saveItems: PatientitemsVO[] = newItems.map(item => ({
|
||||||
|
medicalSn: personParam.value.testNum,
|
||||||
|
itemName: item.name,
|
||||||
|
itemCode: item.itemCode,
|
||||||
|
price: item.price,
|
||||||
|
discountedPrice: item.discountPrice,
|
||||||
|
discounted: item.discount,
|
||||||
|
sectionID: item.sectionID,
|
||||||
|
itemStatus: '0',
|
||||||
|
createTime: new Date().getTime(),
|
||||||
|
headimage: avatar,
|
||||||
|
groupname: item.groupname,
|
||||||
|
groupcode: item.groupcode,
|
||||||
|
mealfrontorafter: item.mealfrontorafter
|
||||||
|
}))
|
||||||
|
|
||||||
|
await PatientitemsApi.createPatientitemsBatch(saveItems)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
message.success('保存成功')
|
message.success('保存成功')
|
||||||
@ -1170,7 +1193,36 @@ watch(() => searchForm_extra.value.passStatus, () => {
|
|||||||
const selectedPatient = ref(null)
|
const selectedPatient = ref(null)
|
||||||
const selectedPatientId = ref(null)
|
const selectedPatientId = ref(null)
|
||||||
|
|
||||||
// 修改加载患者项目的方法,减少不必要的API请求
|
// 添加科室缓存,避免重复请求
|
||||||
|
const departmentCache = ref(new Map())
|
||||||
|
|
||||||
|
// 添加获取科室名称的方法
|
||||||
|
const getSectionName = async (sectionID) => {
|
||||||
|
if (!sectionID) return '暂无科室'
|
||||||
|
|
||||||
|
// 如果缓存中已有该科室,直接返回
|
||||||
|
if (departmentCache.value.has(sectionID)) {
|
||||||
|
return departmentCache.value.get(sectionID)
|
||||||
|
}
|
||||||
|
|
||||||
|
try {
|
||||||
|
// 获取所有科室
|
||||||
|
const departments = await DepartmentApi.getListDepartment()
|
||||||
|
|
||||||
|
// 将所有科室信息缓存
|
||||||
|
departments.forEach(dept => {
|
||||||
|
departmentCache.value.set(dept.departmentCode, dept.departmentName)
|
||||||
|
})
|
||||||
|
|
||||||
|
// 返回对应的科室名称
|
||||||
|
return departmentCache.value.get(sectionID) || '暂无科室'
|
||||||
|
} catch (error) {
|
||||||
|
console.error('获取科室信息失败:', error)
|
||||||
|
return '暂无科室'
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// 修改加载患者项目的方法,移除调试日志
|
||||||
const loadPatientProjects = async (medicalSn) => {
|
const loadPatientProjects = async (medicalSn) => {
|
||||||
if (!medicalSn) {
|
if (!medicalSn) {
|
||||||
comboInfoTable1.value = []
|
comboInfoTable1.value = []
|
||||||
@ -1191,16 +1243,26 @@ const loadPatientProjects = async (medicalSn) => {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// 直接从API返回的数据构建项目列表,不再查询项目详情
|
// 直接从API返回的数据构建项目列表,不再查询项目详情
|
||||||
const projectDetails: ProjectDetail[] = patientItemsRes.list.map(item => ({
|
const projectDetails: ProjectDetail[] = []
|
||||||
name: item.itemName,
|
|
||||||
price: item.price || 0,
|
for (const item of patientItemsRes.list) {
|
||||||
discount: item.discounted || 0,
|
// 获取科室名称
|
||||||
discountPrice: item.discountedPrice || 0,
|
const sectionName = await getSectionName(item.sectionID)
|
||||||
moduleName: item.moduleName || '',
|
|
||||||
section: item.section || '',
|
projectDetails.push({
|
||||||
sectionID: item.sectionID || '',
|
name: item.itemName,
|
||||||
itemCode: item.itemCode
|
price: item.price || 0,
|
||||||
}))
|
discount: item.discounted || 0,
|
||||||
|
discountPrice: item.discountedPrice || 0,
|
||||||
|
moduleName: item.moduleName || '',
|
||||||
|
section: sectionName,
|
||||||
|
sectionID: item.sectionID || '',
|
||||||
|
itemCode: item.itemCode,
|
||||||
|
groupname: item.groupname || '', // 添加模块名称
|
||||||
|
groupcode: item.groupcode || '', // 添加模块ID
|
||||||
|
mealfrontorafter: item.mealfrontorafter || '' // 添加餐前餐后
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
// 强制更新视图
|
// 强制更新视图
|
||||||
comboInfoTable1.value = []
|
comboInfoTable1.value = []
|
||||||
@ -1391,7 +1453,7 @@ const handleCheckInfoSelection = (selection) => {
|
|||||||
checkInfoSelectedData.value = selection
|
checkInfoSelectedData.value = selection
|
||||||
}
|
}
|
||||||
|
|
||||||
// 修改确认选择项目的方法
|
// 修改确认选择项目的方法,移除调试日志
|
||||||
const confirmSelectedProjects = async () => {
|
const confirmSelectedProjects = async () => {
|
||||||
try {
|
try {
|
||||||
let selectedProjects: ProjectDetail[] = []
|
let selectedProjects: ProjectDetail[] = []
|
||||||
@ -1424,16 +1486,23 @@ const confirmSelectedProjects = async () => {
|
|||||||
|
|
||||||
if (itemDetail?.list?.[0]) {
|
if (itemDetail?.list?.[0]) {
|
||||||
const item = itemDetail.list[0]
|
const item = itemDetail.list[0]
|
||||||
|
|
||||||
|
// 获取科室名称
|
||||||
|
const sectionName = await getSectionName(item.sectionID)
|
||||||
|
|
||||||
processedItemCodes.add(moduleItem.itemCode)
|
processedItemCodes.add(moduleItem.itemCode)
|
||||||
selectedProjects.push({
|
selectedProjects.push({
|
||||||
name: item.itemName,
|
name: item.itemName,
|
||||||
section: item.section, // 使用科室名称
|
section: sectionName,
|
||||||
sectionID: item.sectionID, // 保存科室ID用于后端
|
sectionID: item.sectionID,
|
||||||
price: item.price || 0,
|
price: item.price || 0,
|
||||||
discount: item.discounted || 0,
|
discount: item.discounted || 0,
|
||||||
discountPrice: item.discountedPrice || 0,
|
discountPrice: item.discountedPrice || 0,
|
||||||
moduleName: item.moduleName || moduleItem.examModuleName,
|
moduleName: item.moduleName || moduleItem.examModuleName,
|
||||||
itemCode: moduleItem.itemCode
|
itemCode: moduleItem.itemCode,
|
||||||
|
groupname: item.groupname || '',
|
||||||
|
groupcode: item.groupcode || '',
|
||||||
|
mealfrontorafter: item.mealfrontorafter || ''
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
} catch (itemError) {
|
} catch (itemError) {
|
||||||
@ -1450,16 +1519,22 @@ const confirmSelectedProjects = async () => {
|
|||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// 获取科室名称
|
||||||
|
const sectionName = await getSectionName(item.sectionID)
|
||||||
|
|
||||||
processedItemCodes.add(item.itemCode)
|
processedItemCodes.add(item.itemCode)
|
||||||
selectedProjects.push({
|
selectedProjects.push({
|
||||||
name: item.itemName,
|
name: item.itemName,
|
||||||
section: item.section, // 使用科室名称
|
section: sectionName,
|
||||||
sectionID: item.sectionID, // 保存科室ID用于后端
|
sectionID: item.sectionID,
|
||||||
price: item.price,
|
price: item.price,
|
||||||
discount: item.discounted,
|
discount: item.discounted,
|
||||||
discountPrice: item.discountedPrice,
|
discountPrice: item.discountedPrice,
|
||||||
moduleName: item.moduleName,
|
moduleName: item.moduleName,
|
||||||
itemCode: item.itemCode
|
itemCode: item.itemCode,
|
||||||
|
groupname: item.groupname || '',
|
||||||
|
groupcode: item.groupcode || '',
|
||||||
|
mealfrontorafter: item.mealfrontorafter || ''
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -1509,6 +1584,9 @@ interface ProjectDetail {
|
|||||||
discountPrice: number
|
discountPrice: number
|
||||||
moduleName: string
|
moduleName: string
|
||||||
itemCode: string
|
itemCode: string
|
||||||
|
groupname?: string // 添加模块名称
|
||||||
|
groupcode?: string // 添加模块ID
|
||||||
|
mealfrontorafter?: string // 添加餐前餐后
|
||||||
}
|
}
|
||||||
|
|
||||||
// 添加删除选中项目的方法
|
// 添加删除选中项目的方法
|
||||||
|
Loading…
Reference in New Issue
Block a user