inspect-front/src/views/Department-entry/Medical-examination-vehicle.vue
2025-05-23 17:13:39 +08:00

4150 lines
111 KiB
Vue
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

<template>
<div class="medical-report">
<!-- 左侧人员列表 -->
<div class="patient-list">
<div class="list-header">
<div class="filter-options">
<div class="header-title">
<span>患者列表</span>
<div class="header-buttons">
<el-button
type="primary"
size="small"
@click="handleSync"
:icon="RefreshRight"
:disabled="
statusFilter === '1' ||
(selectedPatient &&
(selectedPatient.status === '1' || selectedPatient.status === 1))
"
>
同步
</el-button>
<el-button
type="success"
size="small"
@click="handleRefresh"
:icon="Refresh"
:loading="loading"
>
刷新列表
</el-button>
</div>
</div>
</div>
<!-- 添加检查状态筛选 -->
<div class="status-filter">
<el-radio-group
v-model="statusFilter"
@change="handleStatusFilterChange"
:disabled="loading"
>
<el-radio label="0">待检查</el-radio>
<el-radio label="1">已检查</el-radio>
<el-radio label="2">已打印</el-radio>
</el-radio-group>
</div>
<!-- 添加日期选择器 -->
<div class="date-picker-container" v-if="statusFilter === '2'">
<el-date-picker
v-model="dateRange"
type="daterange"
range-separator="至"
start-placeholder="开始日期"
end-placeholder="结束日期"
value-format="YYYY-MM-DD"
@change="handleDateRangeChange"
size="small"
style="width: 100%"
:disabled="loading"
/>
</div>
<!-- 简化体检编号搜索框 -->
<div class="search-box medical-sn-search">
<input
v-model="searchQuery"
placeholder="请输入姓名/体检编号/身份证"
@keydown.enter="handleLocalSearch"
:disabled="loading"
/>
</div>
</div>
<div class="list-content">
<div v-if="loading" class="loading-container">
<el-skeleton :rows="5" animated />
</div>
<template v-else>
<div
v-for="patient in filteredPatients"
:key="patient.id"
class="patient-item"
@click="handlePatientSelect(patient)"
:class="{ active: selectedPatient?.id === patient.id }"
>
<div class="patient-info">
<div class="info-row">
<span class="name">{{ patient.pname }}</span>
<span class="medical-sn">{{ truncateMedicalSn(patient.medicalSn) }}</span>
<el-tag
size="small"
:type="getStatusInfo(patient).color"
class="status-tag"
>
{{ getStatusInfo(patient).text }}
</el-tag>
<el-button
v-if="getStatusInfo(patient).showButton"
type="primary"
size="small"
@click.stop="resetPatientStatus(patient)"
class="reset-status-btn"
>
撤回
</el-button>
</div>
</div>
</div>
</template>
<!-- 将分页组件移到list-content外部底部 -->
<div class="pagination-container">
<el-pagination
v-model:current-page="pageNo"
:page-size="pageSize"
small
:total="total"
:pager-count="3"
layout="total, prev, pager, next"
@current-change="handleCurrentChange"
>
<template #total>
<span>共 {{ total }} 条</span>
</template>
</el-pagination>
</div>
</div>
</div>
<!-- 右侧内容区域 -->
<div class="right-content">
<!-- 常规检查结果界面 -->
<div class="report-content" v-if="selectedPatient">
<!-- 基本信息 -->
<div class="basic-info">
<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>{{ 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="result-table">
<!-- 汇总页面 -->
<Summary
v-if="currentTab === 'summary'"
:patient="selectedPatient"
:report-data="reportData"
:conclusion-data="conclusionData"
ref="summaryRef"
/>
<!-- 特殊检查类型 -->
<All v-else-if="isSpecialExam" :patient="selectedPatient" :exam-type="currentTab" />
<!-- 常规检查项目表格 -->
<template v-else>
<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 v-if="sortedExamItems.length === 0" class="empty-content">
<el-empty description="暂无检查项目" />
</div>
<div v-else>
<div
v-for="(item, index) in sortedExamItems"
:key="item.id"
class="table-row"
:class="{ 'danger-row': item.status === 'danger' }"
:data-item-status="item.itemStatus"
>
<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%">
<input
type="text"
v-model="item.value"
@change="handleResultChange(item)"
@click="checkEditPermission"
class="cell-input"
:readonly="isReadOnly"
/>
</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"
class="positive-indicator"
>
阳性
</el-tag>
<span v-else class="negative-text">阴性</span>
</div>
<div class="table-cell" style="width: 10%">
<el-dropdown @command="handleOperation">
<el-button size="small" :class="{ 'view-only': isReadOnly }">
更多操作
<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>
</template>
</div>
<!-- 修改体检小结部分 -->
<div
v-if="['ultrasound', 'ecg'].includes(currentTab)"
class="findings-diagnosis-container"
>
<div class="findings-section">
<div class="section-title">
<span class="title-text">
检查所见
<el-button
type="text"
@click="openTemplateDrawer(null, 'finding')"
:disabled="isReadOnly"
>
诊断模板
</el-button>
<span class="save-btn-container">
<el-button
type="text"
class="save-btn"
@click="handleSaveCurrentTab"
:disabled="isReadOnly"
>
保存小结
</el-button>
<el-button
type="text"
class="abandon-btn"
@click="handleAbandonExam"
:disabled="isReadOnly"
style="color: red"
>
弃检
</el-button>
</span>
</span>
</div>
<textarea
v-model="conclusionData[currentTab].finding"
placeholder="请输入检查所见"
class="findings-textarea"
:readonly="isReadOnly"
></textarea>
</div>
<div class="diagnosis-section">
<div class="section-title">
<span class="title-text">
检查结果
<el-button
type="text"
@click="openTemplateDrawer(null, 'diagnosis')"
:disabled="isReadOnly"
>
诊断模板
</el-button>
</span>
</div>
<textarea
v-model="conclusionData[currentTab].diagnosis"
placeholder="请输入检查结果"
class="diagnosis-textarea"
:readonly="isReadOnly"
></textarea>
</div>
</div>
<!-- 其他类型使用单栏小结,但不包括汇总标签 -->
<div v-else-if="currentTab !== 'summary'" class="summary-section">
<div class="section-title">
<span class="title-text">
体检小结
<el-button
type="text"
@click="openTemplateDrawer('summary')"
:disabled="isReadOnly"
>
诊断模板
</el-button>
<span class="save-btn-container">
<el-button
type="text"
class="save-btn"
@click="handleSaveCurrentTab"
:disabled="isReadOnly"
>
保存小结
</el-button>
<el-button
type="text"
class="abandon-btn"
@click="handleAbandonExam"
:disabled="isReadOnly"
style="color: red"
>
弃检
</el-button>
</span>
</span>
</div>
<textarea
v-model="currentSummary"
placeholder="输入多个以分号隔开"
class="summary-textarea"
:readonly="isReadOnly"
></textarea>
</div>
</div>
<!-- 底部操作栏 -->
<div class="action-footer">
<div class="left-section">
<div class="doctor-select-container">
<span>检查医生:</span>
<!-- 根据检查状态显示不同内容 -->
<template v-if="isExamCompleted">
<span>{{ inspectDoctor }}</span>
</template>
<template v-else>
<!-- 修改选择控件 -->
<el-select
v-model="inspectDoctor"
placeholder="请选择检查医生"
:disabled="isDisabled"
class="doctor-select"
clearable
>
<el-option
v-for="item in doctorList"
:key="item.value"
:label="item.label"
:value="item.value"
/>
</el-select>
</template>
</div>
<div class="date-container">
<span>检查日期:</span>
<span>{{ inspectTime || formatDate(new Date()) }}</span>
</div>
</div>
<div class="right-section">
<div class="action-buttons">
<button
class="action-btn primary"
@click="handleSaveAllResults"
:disabled="isDisabled"
>
保存所有结果
</button>
</div>
</div>
</div>
</div>
</div>
</div>
<!-- 添加模板抽屉组件 -->
<template-drawer
v-model="drawerVisible"
:template-type="currentTemplateType"
@select-template="insertTemplate"
/>
</template>
<script setup>
import { ref, onMounted, computed, onBeforeUnmount, watch } from 'vue'
import { ElDialog, ElLoading, ElMessage, ElMessageBox } from 'element-plus'
import { PatientApi } from '@/api/inspect/inspectpatient'
import { PatientitemsApi } from '@/api/inspect/inspectpatientitems'
import { getUserProfile } from '@/api/system/user/profile'
import ExamImages from './Exam_images.vue'
import { ArrowDown, Refresh, RefreshRight } from '@element-plus/icons-vue'
import All from './All.vue'
import { PacsDataApi } from '@/api/inspect/inspectpacsdata'
import { getStrDictOptions } from '@/utils/dict'
import Summary from './summary.vue'
import TemplateDrawer from './Drawer-Template.vue'
import { updateItemsAnalyse } from '@/api/summary'
import { DoctorApi } from '@/api/inspect/inspectdoctor'
import { debounce } from 'lodash-es' // 添加lodash-es的debounce
import { InspectOrgApi } from '@/api/inspect/inspectorg'
const dialogTitle = ref('体检报告')
const { t } = useI18n() // 国际化
const message = useMessage() // 消息弹窗
const status = ref('')
const patients = ref([])
// 患者基本信息数据
const reportData = ref({
medicalSn: '', // 体检编号
cardId: '', // 证件ID
pName: '', // 患者姓名
gender: '', // 性别
birthday: '', // 出生日期
nationality: '', // 国籍
nation: '', // 民族
race: '', // 人种
phoneNum: '', // 电话
status: 0, // 状态
reportType: '', // 报告类型
medicalDateTime: '', // 体检日期
chargeType: '', // 收费方式
totalPrice: 0, // 实际收款金额
headPicUrl: '', // 头像图片路径
summaryResult: '', // 汇总分析结果
auditor: '', // 审核人
auditorTime: '' // 审核时间
})
// 患者体检项目数据
const patientitemData = ref({
medicalSn: '', // 体检编号
itemName: '', // 检查项目名称
itemCode: '', // 项目代号
price: 0, // 项目单价
discountedPrice: 0, // 折扣价
discounted: 0, // 折扣 百分比
sectionID: '', // 科室ID
examDescription: '', // 检查所见
itemResult: '', // 检查结论
unit: '', // 项目单位
highValue: 0, // 取值上限
lowValue: 0, // 取值下限
itemStatus: '', // 0未检 1已检 2放弃 3挂起择日检(待查)
createTime: '', // 创建时间
positive: '', // 是否阳性 1阳性
inspectdoctor: '', // 检查医生
inspecttime: '' // 检查时间
})
const doctorSignature = ref('')
// 检查项目标签数据
const examTabs = ref([
{ id: 'general', name: '一般检查', color: '#006699' },
{ id: 'ultrasound', name: '超声', color: '#0099CC' },
{ id: 'ecg', name: '心电图', color: '#00CCFF' },
{ id: 'blood', name: '血常规', color: '#66CCFF' },
{ id: 'urine', name: '尿常规', color: '#99CCFF' },
{ id: 'biochemical', name: '生化', color: '#0099CC' },
{ id: 'summary', name: '汇总', color: '#0099CC' }
])
const currentTab = ref('general')
const summaryRef = ref(null)
// 检查结果数据
const examItems = ref({})
// 当前显示的检查结果
const currentExamItems = computed(() => {
return examItems.value[currentTab.value] || []
})
// 添加排序后的计算属性
const sortedExamItems = computed(() => {
if (!currentExamItems.value) return []
// 对当前显示的检查项目进行排序
return [...currentExamItems.value].sort((a, b) => {
// 首先按照 itemStatus 排序(未检的排在前面)
if (a.itemStatus !== b.itemStatus) {
// 优先级:未检(0) > 已检(1) > 待查(3) > 弃检(2)
const statusOrder = { 0: 0, 1: 1, 3: 2, 2: 3 }
return statusOrder[a.itemStatus] - statusOrder[b.itemStatus]
}
// 如果状态相同,则按照 id 排序
return a.id - b.id
})
})
// 修改 switchTab 函数,添加对汇总标签的特殊处理
const switchTab = async (tabId) => {
// 设置新的当前标签
currentTab.value = tabId
}
// 修改 conclusionData 的数据结构,添加 summary 字段,并设置默认值
const conclusionData = ref({
general: { summary: '未见异常' },
ultrasound: { finding: '未见异常', diagnosis: '未见异常' },
ecg: { finding: '详见报告单', diagnosis: '详见报告单' },
blood: { summary: '未见异常' },
urine: { summary: '未见异常' },
biochemical: { summary: '未见异常' },
summary: { summary: '' } // 确保这里有 summary 对象
})
// 其他数据
const examConclusion = ref('')
const examDate = ref('')
const pageNo = ref(1)
const pageSize = ref(20) // 改为20与分页组件一致
const total = ref(0)
// 添加搜索相关的状态
const searchQuery = ref('')
const originalPatients = ref([]) // 保存原始患者列表
// 添加数据缓存
const patientDataCache = ref(new Map())
// 添加体检编号搜索相关
const medicalSnQuery = ref('')
// 添加本地搜索处理函数
const handleLocalSearch = async () => {
if (!searchQuery.value) {
// 如果搜索框为空,恢复原始列表
await getPatientList()
return
}
try {
const loading = ElLoading.service({
lock: true,
text: '搜索中...',
background: 'rgba(255, 255, 255, 0.7)'
})
// 获取搜索结果
const res = await PatientApi.getPatientInfoByMedicalSn(searchQuery.value,user.value.deptId,statusFilter.value)
// 检查返回的数据
if (res) {
if (Array.isArray(res)) {
patients.value = res
total.value = res.length
} else if (res.list && Array.isArray(res.list)) {
patients.value = res.list
total.value = res.total || res.list.length
} else {
console.warn('搜索返回的数据格式不符合预期:', res)
patients.value = []
total.value = 0
}
} else {
console.warn('搜索返回的数据为空')
patients.value = []
total.value = 0
}
loading.close()
} catch (error) {
console.error('搜索患者失败:', error)
if (error.response) {
console.error('服务器响应错误:', error.response)
ElMessage.error(`搜索失败: ${error.response.status} ${error.response.statusText}`)
} else if (error.request) {
console.error('请求错误:', error.request)
ElMessage.error('网络请求失败,请检查网络连接')
} else {
console.error('其他错误:', error.message)
ElMessage.error('搜索失败: ' + error.message)
}
}
}
// 修改获取患者列表数据的函数
const getPatientList = async () => {
try {
const loading = ElLoading.service({
lock: true,
text: '加载中...',
background: 'rgba(255, 255, 255, 0.7)'
})
const params = {
pageNo: pageNo.value,
pageSize: pageSize.value
}
// 根据当前状态筛选值设置不同的查询参数
if (statusFilter.value === '2') {
// 已打印状态,查询 isprint 为 1 的数据
params.isprint = 1
// 如果有机构编码且不为空,添加机构编码查询
if (examhosInfo.value.examhoscode) {
params.examhoscode = examhosInfo.value.examhoscode
}
// 在已打印状态下,如果有日期范围,则添加日期条件
if (dateRange.value && dateRange.value.length === 2) {
const [startDate, endDate] = dateRange.value
params.printTimeRange = [
startDate ? `${startDate} 00:00:00` : null,
endDate ? `${endDate} 23:59:59` : null
]
}
} else {
// 其他状态,使用 status 字段查询
params.status = statusFilter.value
// 如果是已检查状态且有机构编码,添加机构编码查询
if (statusFilter.value === '1' && examhosInfo.value.examhoscode) {
params.examhoscode = examhosInfo.value.examhoscode
}
}
const res = await PatientApi.getPatientPage(params)
if (res) {
// 检查返回的数据结构
if (Array.isArray(res.list)) {
patients.value = res.list
originalPatients.value = res.list
total.value = res.total || res.list.length
} else if (Array.isArray(res)) {
// 如果直接返回数组
patients.value = res
originalPatients.value = res
total.value = res.length
} else {
console.warn('返回的数据格式不符合预期:', res)
patients.value = []
originalPatients.value = []
total.value = 0
}
} else {
console.warn('返回的数据为空')
patients.value = []
originalPatients.value = []
total.value = 0
}
loading.close()
} catch (error) {
console.error('获取患者列表出错:', error)
// 检查错误类型
if (error.response) {
console.error('服务器响应错误:', error.response)
ElMessage.error(`服务器错误: ${error.response.status} ${error.response.statusText}`)
} else if (error.request) {
console.error('请求错误:', error.request)
ElMessage.error('网络请求失败,请检查网络连接')
} else {
console.error('其他错误:', error.message)
ElMessage.error('获取患者列表失败: ' + error.message)
}
}
}
// 修改获取患者体检项目数据的方法
const getpatientitemData = async (medicalSn) => {
try {
const params = {
medicalSn: medicalSn,
pageNo: 1,
pageSize: 100
}
const itemsRes = await PatientitemsApi.getPatientitemsPage(params)
if (itemsRes.list && itemsRes.list.length > 0) {
patientitemData.value = itemsRes.list[0]
// 如果有项目且都是已检查状态,更新患者状态
if (
currentDeptItems.length > 0 &&
currentDeptItems.every((item) => item.itemStatus === '1')
) {
// 更新患者列表中的状态
const patientIndex = patients.value.findIndex((p) => p.medicalSn === medicalSn)
if (patientIndex !== -1) {
patients.value[patientIndex] = {
...patients.value[patientIndex],
examStatus: '1' // 添加检查状态属性
}
}
}
}
} catch (error) {
console.error('获取患者体检项目数据出错:', error)
message.error('获取患者体检项目数据出错')
}
}
// 修改 loadPatientData 函数,确保正确加载已检查患者的医生和日期
const loadPatientData = async (patient) => {
try {
const loading = ElLoading.service({
lock: true,
text: '加载中...',
background: 'rgba(255, 255, 255, 0.7)'
})
try {
// 获取患者基本信息
const patientData = await PatientApi.getPatient(patient.id)
reportData.value = patientData
// 保存当前选择的医生,只在需要时重置
const currentDoctor = inspectDoctor.value
// 重置检查日期
inspectTime.value = ''
// 检查患者状态如果已检查则设置检查完成状态为true
isExamCompleted.value = patient.status === '1' || patient.status === 1
// 获取检查项目
const itemsRes = await PatientitemsApi.getPatientitemsPage({
medicalSn: patient.medicalSn,
pageNo: 1,
pageSize: 100
})
// 处理检查项目数据
if (itemsRes.list && itemsRes.list.length > 0) {
// 按照类别分组
const groupedItems = {}
// 根据不同类型的检查项目,加载对应的小结
const conclusions = {
general: { summary: '未见异常' },
ultrasound: { finding: '未见异常', diagnosis: '未见异常' },
ecg: { finding: '详见报告单', diagnosis: '详见报告单' },
blood: { summary: '' },
urine: { summary: '未见异常' },
biochemical: { summary: '' }
}
// 查找已检查的项目,获取检查医生和日期
const checkedItems = itemsRes.list.filter((item) => item.itemStatus === '1')
let foundDoctorInfo = false
if (checkedItems.length > 0) {
// 使用第一个已检查项目的检查医生和日期
const firstCheckedItem = checkedItems[0]
// 设置检查医生
if (firstCheckedItem.inspectdoctor) {
inspectDoctor.value = firstCheckedItem.inspectdoctor
foundDoctorInfo = true
}
// 格式化检查时间
if (firstCheckedItem.inspecttime) {
const inspectDate = new Date(Number(firstCheckedItem.inspecttime))
inspectTime.value = formatDate(inspectDate)
}
}
// 如果未找到已检查项目的医生信息且不是已检查状态,则保留当前选择的医生
if (!foundDoctorInfo && !isExamCompleted.value && currentDoctor) {
inspectDoctor.value = currentDoctor
}
// 用于存储异常信息
let abnormalSummary = []
itemsRes.list.forEach((item) => {
// 处理项目分类
const category = getCategoryByItemName(item.itemName || '')
if (!groupedItems[category]) {
groupedItems[category] = []
}
// 处理项目数据
const processedItem = processItemData(item)
groupedItems[category].push(processedItem)
// 处理小结数据
processConclusion(item, category, conclusions)
// 处理BMI项目
if (item.itemName && item.itemName.includes('体质指数') && item.itemName.includes('BMI') && item.itemResult) {
handleBmiResult(processedItem)
}
// 处理血压项目
if (item.itemName && item.itemName.includes('血压') && item.itemResult) {
const bpMatch = item.itemResult.match(/(\d+)\/(\d+)/)
if (bpMatch) {
const systolic = parseInt(bpMatch[1]) // 收缩压
const diastolic = parseInt(bpMatch[2]) // 舒张压
if (!isNaN(systolic) && !isNaN(diastolic)) {
if (systolic >= 130 || diastolic >= 85) {
processedItem.note = '↑'
processedItem.risk = '血压偏高'
processedItem.status = 'danger'
abnormalSummary.push('【血压】' + item.itemResult + ',偏高')
} else {
processedItem.note = '-'
processedItem.risk = '正常'
processedItem.status = ''
}
}
}
}
})
// 如果患者状态是待检查且当前小结是"未见异常",则更新小结
if (patient.status !== '1' && patient.status !== 1 &&
conclusions.general.summary === '未见异常' &&
abnormalSummary.length > 0) {
conclusions.general.summary = abnormalSummary.join('')
}
examItems.value = groupedItems
conclusionData.value = conclusions
}
// 新增PACS数据获取
try {
// 直接获取所有PACS数据
const res = await PacsDataApi.getPacsDataDetail(patient.medicalSn)
if (res && res.length > 0) {
// 按type分组处理数据
const typeGroups = {}
// 遍历所有返回的数据按type分组
res.forEach((item) => {
if (item.type && item.item) {
if (!typeGroups[item.type]) {
typeGroups[item.type] = []
}
typeGroups[item.type].push(item.item)
}
})
// 处理不同类型的数据到对应标签页
// 类型映射关系
const typeToTabMapping = {
cbc: 'blood', // 血常规
rt: 'urine', // 尿常规
bt: 'biochemical' // 生化
}
// 遍历所有类型组
Object.entries(typeGroups).forEach(([type, items]) => {
// 转换为小写以便匹配
const lowerType = type.toLowerCase()
// 获取对应的标签页
const tabKey = typeToTabMapping[lowerType]
if (tabKey) {
// 将该类型的所有项目合并
const combinedData = items.join(';')
// 其他类型直接赋值到summary
conclusionData.value[tabKey].summary = combinedData
// 更新对应检查项目
if (examItems.value[tabKey]) {
examItems.value[tabKey].forEach((item) => {
// 根据项目名称匹配
if (item.name.toLowerCase().includes(tabKey)) {
item.value = combinedData
item.itemStatus = '1' // 设置为已检查状态
}
})
}
}
})
}
} catch (error) {
console.error('获取PACS数据失败:', error)
}
} catch (error) {
console.error('加载患者数据失败:', error)
ElMessage.error('加载患者数据失败')
} finally {
loading.close()
}
} catch (error) {
console.error('加载患者数据失败:', error)
ElMessage.error('加载患者数据失败')
}
}
// 修改 handlePatientSelect 函数,确保正确设置检查完成状态
const handlePatientSelect = async (patient) => {
try {
// 清理当前数据
examConclusion.value = ''
examItems.value = {}
// 重置体检小结数据,避免缓存问题
conclusionData.value = {
general: { summary: '未见异常' },
ultrasound: { finding: '未见异常', diagnosis: '未见异常' },
ecg: { finding: '详见报告单', diagnosis: '详见报告单' },
blood: { summary: '' },
urine: { summary: '未见异常' },
biochemical: { summary: '' },
summary: { summary: '' }
}
// 设置选中患者
selectedPatient.value = patient
// 根据患者状态设置检查完成状态
isExamCompleted.value = patient.status === '1' || patient.status === 1
// 加载患者数据,包括设置检查医生等
await loadPatientData(patient)
currentTab.value = 'general'
} catch (error) {
console.error('[handlePatientSelect] 切换患者失败:', error)
message.error('切换患者失败')
}
}
// 辅助函数:根据项目名称获取分类
const getCategoryByItemName = (itemName) => {
itemName = itemName.toLowerCase()
if (itemName.includes('超声') || itemName.includes('彩超') || itemName.includes('b超')) {
return 'ultrasound'
} else if (itemName.includes('心电图') || itemName.includes('ecg') || itemName.includes('ekg')) {
return 'ecg'
} else if (
itemName.includes('血常规') ||
itemName.includes('血细胞') ||
itemName.includes('血红蛋白')
) {
return 'blood'
} else if (itemName.includes('尿常规') || itemName.includes('尿液分析')) {
return 'urine'
} else if (
itemName.includes('生化') ||
itemName.includes('肝功能') ||
itemName.includes('肾功能') ||
itemName.includes('血脂') ||
itemName.includes('血糖') ||
itemName.includes('电解质')
) {
return 'biochemical'
} else {
return 'general'
}
}
// 辅助函数:处理项目数据
const processItemData = (item) => {
return {
id: item.id,
name: item.itemName,
code: item.itemCode,
value: item.itemResult,
originalValue: item.itemResult,
unit: item.unit,
reference:
item.lowValue !== null && item.highValue !== null
? `${item.lowValue}-${item.highValue}`
: 'null-null',
status: getRowStatus(item),
risk: getRiskLevel(item),
note: getStatusNote(item),
itemStatus: item.itemStatus || '0',
sectionID: item.sectionID
}
}
// 辅助函数:处理小结数据
const processConclusion = (item, category, conclusions) => {
if (category === 'ultrasound' || category === 'ecg') {
// 处理超声和心电图的所见和结果
if (item.examDescription && item.examDescription.trim()) {
conclusions[category].finding = item.examDescription
}
if (item.itemResult && item.itemResult.trim()) {
conclusions[category].diagnosis = item.itemResult
}
// 如果有analyse字段尝试从中解析检查所见和结果
if (item.analyse) {
const parts = item.analyse.split('\n')
parts.forEach((part) => {
if (part.startsWith('检查所见:')) {
const finding = part.replace('检查所见:', '').trim()
if (finding) conclusions[category].finding = finding
} else if (part.startsWith('检查结果:')) {
const diagnosis = part.replace('检查结果:', '').trim()
if (diagnosis) conclusions[category].diagnosis = diagnosis
}
})
}
} else {
// 处理其他类型的小结 - 只使用analyse字段
if (item.analyse && item.analyse.trim()) {
conclusions[category].summary = item.analyse
}
}
}
// 修改获取状态提示的函数
const getStatusNote = (item) => {
if (!item.reference || item.reference === 'null-null') {
return ''
}
const value = parseFloat(item.itemResult)
const [low, high] = item.reference.split('-').map((val) => (val === 'null' ? null : Number(val)))
if (low === null || high === null) {
return ''
}
if (value < low) return '↓'
if (value > high) return '↑'
return '-'
}
// 修改获取风险等级的函数
const getRiskLevel = (item) => {
if (!item.reference || item.reference === 'null-null') {
return ''
}
const value = parseFloat(item.itemResult)
const [low, high] = item.reference.split('-').map((val) => (val === 'null' ? null : Number(val)))
if (low === null || high === null) {
return ''
}
if (value < low) return '低于正常值'
if (value > high) return '高于正常值'
return '正常'
}
// 修改获取行状态的函数
const getRowStatus = (item) => {
if (!item.reference || item.reference === 'null-null') {
return ''
}
const value = parseFloat(item.itemResult)
const [low, high] = item.reference.split('-').map((val) => (val === 'null' ? null : Number(val)))
if (low === null || high === null) {
return ''
}
if (value > high) {
return 'danger'
}
return ''
}
// 添加处理BMI指数的函数
const handleBmiResult = (item) => {
if (!item.value) return
const bmiValue = parseFloat(item.value)
if (isNaN(bmiValue)) return
let bmiStatus = ''
// BMI判断标准体重过低<18.5正常18.5≤BMI<24超重24≤BMI<28肥胖28≤BMI
if (bmiValue < 18.5) {
item.note = '↓'
item.risk = '体重过低'
item.status = 'danger'
bmiStatus = `【体质指数(BMI)】${bmiValue},体重过低`
} else if (bmiValue >= 18.5 && bmiValue < 24) {
item.note = '-'
item.risk = '正常'
item.status = ''
// 正常值不添加到小结
} else if (bmiValue >= 24 && bmiValue < 28) {
item.note = '↑'
item.risk = '超重'
item.status = 'danger'
bmiStatus = `【体质指数(BMI)】${bmiValue},超重`
} else if (bmiValue >= 28) {
item.note = '↑↑'
item.risk = '肥胖'
item.status = 'danger'
bmiStatus = `【体质指数(BMI)】${bmiValue},肥胖`
}
// 直接更新一般检查小结
updateGeneralSummary(bmiStatus)
}
// 添加处理血压的函数
const handleBloodPressureResult = (item) => {
if (!item.value) return
// 血压值通常是systolic/diastolic格式例如 125/90
const bpMatch = item.value.match(/(\d+)\/(\d+)/)
if (!bpMatch) return
const systolic = parseInt(bpMatch[1]) // 收缩压
const diastolic = parseInt(bpMatch[2]) // 舒张压
let bpStatus = ''
if (isNaN(systolic) || isNaN(diastolic)) return
// 判断标准: 收缩压<130 且 舒张压<85为正常
if (systolic >= 130 || diastolic >= 85) {
item.note = '↑'
item.risk = '血压偏高'
item.status = 'danger'
bpStatus = `【血压】${item.value},偏高`
} else {
item.note = '-'
item.risk = '正常'
item.status = ''
// 正常值不添加到小结
}
// 直接更新一般检查小结
updateGeneralSummary(bpStatus)
}
// 添加更新一般检查小结的函数
const updateGeneralSummary = (newStatus) => {
if (!newStatus) return // 如果没有异常状态,不更新小结
// 获取当前小结内容
let currentSummary = conclusionData.value.general.summary || '未见异常'
// 处理关键词,提取括号中内容作为判断依据
const keywordMatch = newStatus.match(/【(.+?)】/)
if (!keywordMatch) return
const keyword = keywordMatch[1]
// 如果当前是"未见异常",直接替换为新状态
if (currentSummary === '未见异常') {
conclusionData.value.general.summary = newStatus
return
}
// 检查小结中是否已包含相同关键词的内容
if (currentSummary.includes(`${keyword}`)) {
// 如果已包含相同关键词,替换该部分内容
const regex = new RegExp(`${keyword}】[^;。]+[;。]?`, 'g')
currentSummary = currentSummary.replace(regex, '')
// 清理可能留下的多余分隔符
currentSummary = currentSummary.replace(/+/g, '').trim()
// 如果替换后内容为空,设置为新状态
if (!currentSummary || currentSummary === '') {
conclusionData.value.general.summary = newStatus
} else {
// 否则添加到末尾
conclusionData.value.general.summary = currentSummary + (currentSummary.endsWith('') ? '' : '') + newStatus
}
} else {
// 如果不包含相同关键词,添加到末尾
conclusionData.value.general.summary = currentSummary + (currentSummary.endsWith('') ? '' : '') + newStatus
}
// 清理多余的分隔符
conclusionData.value.general.summary = conclusionData.value.general.summary.replace(/{2,}/g, '')
}
// 修改科室名称映射函数
const getSectionName = (sectionId) => {
// 获取该科室下的所有检查项目
const items = examItems.value[sectionId] || []
// 检查是否包含特定检查项目
const hasBloodTest = items.some((item) => item.name.includes('血常规'))
const hasUrineTest = items.some((item) => item.name.includes('尿常规'))
const hasImageTest = items.some(
(item) =>
item.name.includes('CT') ||
item.name.includes('MRI') ||
item.name.includes('超声') ||
item.name.includes('X线') ||
item.name.includes('影像')
)
// 根据检查项目类型返回对应科室名称
if (hasBloodTest) return '血液检查'
if (hasUrineTest) return '尿液检查'
if (hasImageTest) return '影像检查'
return '一般检查'
}
// 标签颜色映射
const tabColors = ['#003366', '#006699', '#0099CC', '#00CCFF', '#0099CC']
const getTabColor = (index) => {
return tabColors[index % tabColors.length]
}
onMounted(async () => {
try {
loading.value = true
// 首先获取用户信息
const userProfile = await getUserProfile()
user.value = userProfile
// 获取机构信息
if (userProfile?.deptId) {
const deptInfo = await InspectOrgApi.getInspectOrg(userProfile.deptId)
if (deptInfo) {
examhosInfo.value.examhoscode = deptInfo.orgid || ''
examhosInfo.value.examhosname = deptInfo.orgName || ''
console.log('体检机构信息:', examhosInfo.value)
}
}
// 然后获取医生列表(会自动匹配当前用户)
await getDoctorList()
// 初始化患者列表
await getPatientList()
// 如果检查医生没有设置,但用户有昵称,再次尝试匹配医生
if (!inspectDoctor.value && user.value?.nickname && doctorList.value.length > 0) {
const matchedOption = doctorList.value.find(item =>
item.label === user.value.nickname
)
if (matchedOption) {
inspectDoctor.value = matchedOption.value
console.log('在onMounted中设置默认检查医生:', inspectDoctor.value)
}
}
} catch (error) {
console.error('初始化组件失败:', error)
ElMessage.error('初始化组件失败,请刷新页面重试')
} finally {
loading.value = false
}
})
// 修改处理时间周期切换的函数
const handlePeriodChange = (period) => {
selectedPeriod.value = period
// 清除选中状态
selectedPatient.value = null
if (period === 'reset') {
// 重置所有筛选条件
selectedPeriod.value = '' // 清除选中的时间周期
customDateRange.value = [] // 清除日期范围
showDatePicker.value = false
// 重新获取所有数据,不带日期过滤
getPatientList()
return
}
const today = new Date()
let startDate, endDate
switch (period) {
case 'today':
startDate = new Date(today.setHours(0, 0, 0, 0))
endDate = new Date(today.setHours(23, 59, 59, 999))
customDateRange.value = [startDate, endDate]
showDatePicker.value = false
fetchPatientsByDate()
break
case 'week':
startDate = new Date(today)
startDate.setDate(today.getDate() - today.getDay())
endDate = new Date(today)
endDate.setDate(startDate.getDate() + 6)
customDateRange.value = [startDate, endDate]
showDatePicker.value = false
fetchPatientsByDate()
break
case 'month':
startDate = new Date(today.getFullYear(), today.getMonth(), 1)
endDate = new Date(today.getFullYear(), today.getMonth() + 1, 0)
customDateRange.value = [startDate, endDate]
showDatePicker.value = false
fetchPatientsByDate()
break
case 'custom':
showDatePicker.value = !showDatePicker.value
break
}
}
// 修改按日期获取患者列表方法 - 添加机构编码
const fetchPatientsByDate = async () => {
try {
if (!customDateRange.value || customDateRange.value.length !== 2) return
const [startDate, endDate] = customDateRange.value
const params = {
pageNo: pageNo.value,
pageSize: pageSize.value,
medicalDateTime: [`${formatDate(startDate)} 00:00:00`, `${formatDate(endDate)} 23:59:59`]
}
// 如果有机构编码,添加到查询条件
if (examhosInfo.value.examhoscode) {
params.examhoscode = examhosInfo.value.examhoscode
}
const res = await PatientApi.getPatientPage(params)
patients.value = res.list
originalPatients.value = res.list
total.value = res.total
// 如果没有查询到患者,清除右侧详情
if (!res.list || res.list.length === 0) {
selectedPatient.value = null
}
} catch (error) {
console.error('按日期获取患者列表失败:', error)
message.error('获取患者列表失败')
}
}
// 修改日期搜索处理方法
const handleDateSearch = () => {
if (customDateRange.value && customDateRange.value.length === 2) {
fetchPatientsByDate()
} else {
message.warning('请选择日期范围')
}
}
// 添加格式化后的检查日期计算属性
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 age = computed(() => {
if (!reportData.value.cardId) return ''
// 从身份证号提取出生日期
const idCard = reportData.value.cardId
if (idCard.length !== 18) return '' // 确保是18位身份证
// 提取出生年月日 (格式为 YYYYMMDD)
const birthYear = idCard.substring(6, 10)
const birthMonth = idCard.substring(10, 12)
const birthDay = idCard.substring(12, 14)
const birthDate = new Date(`${birthYear}-${birthMonth}-${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 gender = computed(() => {
// 直接使用reportData中的gender字段
return reportData.value.gender || ''
})
// 添加选中患者的状态
const selectedPatient = ref(null)
// 添加用户信息的响应式引用
const user = ref(null)
// 添加计算属性检查是否所有项目都已完成
const isAllItemsChecked = computed(() => {
if (!sortedExamItems.value || sortedExamItems.value.length === 0) return false
return sortedExamItems.value.every((item) => item.itemStatus === '1')
})
// 修改检查编辑权限的方法
const checkEditPermission = () => {
// 检查当前患者的检查状态
if (
selectedPatient.value &&
(selectedPatient.value.status === '1' || selectedPatient.value.status === 1)
) {
ElMessage.warning('该患者检查已完成,不可进行编辑')
return false
}
// 检查当前科室的检查项目是否全部完成
const currentDeptItems = Object.values(examItems.value)
.flat()
.filter((item) => item.sectionID === user.value?.deptId)
if (currentDeptItems.length > 0 && currentDeptItems.every((item) => item.itemStatus === '1')) {
ElMessage.warning('所有检查项目已完成,不可进行编辑')
return false
}
return true
}
// 修改同步结果处理函数
const handleSync = async () => {
try {
const loading = ElLoading.service({
lock: true,
text: '同步中...',
background: 'rgba(255, 255, 255, 0.7)'
})
try {
if (!selectedPatient.value?.medicalSn) {
throw new Error('未选择患者或体检编号为空')
}
// 保存当前选中的患者,以便在同步后恢复选中状态
const currentSelectedPatient = { ...selectedPatient.value }
const medicalSn = currentSelectedPatient.medicalSn
// 定义需要同步的类型
const types = ['XCG', 'NCG', 'SHQX', 'ECG', 'YBJC']
// 首先检查每种类型是否已存在数据
const existingDataPromises = types.map((type) =>
PacsDataApi.getPacsDataPage({
code: medicalSn,
type: type,
pageNo: 1,
pageSize: 1
}).catch((error) => {
console.warn(`检查${type}数据是否存在时出错:`, error)
return { list: [] }
})
)
// 检查超声数据是否存在
const usExistingData = await PacsDataApi.getPacsDataPage({
code: medicalSn,
type: 'US',
pageNo: 1,
pageSize: 1
}).catch((error) => {
console.warn('检查超声数据是否存在时出错:', error)
return { list: [] }
})
// 检查心电图数据是否存在
const ecgExistingData = await PacsDataApi.getPacsDataPage({
code: medicalSn,
type: 'ECG',
pageNo: 1,
pageSize: 1
}).catch((error) => {
console.warn('检查心电图数据是否存在时出错:', error)
return { list: [] }
})
// 获取所有类型的现有数据结果
const existingDataResults = await Promise.all(existingDataPromises)
// 确定哪些类型需要同步
const typesToSync = []
existingDataResults.forEach((result, index) => {
const type = types[index]
// 如果没有数据或数据为空,则需要同步
const needsSync =
!result.list ||
result.list.length === 0 ||
(result.list[0] && (!result.list[0].data || result.list[0].data === ''))
if (needsSync) {
typesToSync.push(type)
} else {
console.log(`${type}数据已存在且不为空,跳过同步`)
}
})
// 检查超声数据是否需要同步
const needsSyncUS =
!usExistingData.list ||
usExistingData.list.length === 0 ||
(usExistingData.list[0] &&
(!usExistingData.list[0].data || usExistingData.list[0].data === ''))
// 检查心电图数据是否需要同步
const needsSyncECG =
!ecgExistingData.list ||
ecgExistingData.list.length === 0 ||
(ecgExistingData.list[0] &&
(!ecgExistingData.list[0].data || ecgExistingData.list[0].data === ''))
// 准备同步请求
const syncPromises = []
// 添加需要同步的检验报告请求
typesToSync.forEach((type) => {
syncPromises.push(
PatientApi.getReportTj(medicalSn, type).catch((error) => {
console.warn(`获取${type}报告失败:`, error)
return null
})
)
})
// 直接添加超声报告请求,无需检查是否存在数据
syncPromises.push(
PatientApi.getUSTj(medicalSn).catch((error) => {
console.warn('获取超声报告失败:', error)
return null
})
)
// 如果需要,添加心电图报告请求
if (needsSyncECG) {
syncPromises.push(
PatientApi.GetApiEcgInfo(medicalSn).catch((error) => {
console.warn('获取心电图报告失败:', error)
return null
})
)
}
// 如果需要,添加一般检查报告请求
if (typesToSync.includes('YBJC')) {
syncPromises.push(
PatientApi.GetApiYbjcInfo(medicalSn, currentSelectedPatient.cardId).catch((error) => {
console.warn('获取一般检查报告失败:', error)
return null
})
)
}
// 如果需要,添加中医体质辨识报告请求
await PatientApi.getZytzInfo(medicalSn, currentSelectedPatient.cardId)
// 如果没有需要同步的项目,直接返回
if (syncPromises.length === 0) {
loading.close()
ElMessage.info('所有报告数据已存在,无需同步')
return
}
const results = await Promise.all(syncPromises)
// 检查是否所有请求都失败了
const allFailed = results.every((result) => result === null)
if (allFailed) {
throw new Error('所有报告同步失败')
}
// 处理同步结果
let successCount = 0
results.forEach((result) => {
if (result) {
successCount++
}
})
// 等待一小段时间确保后端数据同步完成
await new Promise((resolve) => setTimeout(resolve, 1000))
// 清除缓存
patientDataCache.value.clear()
// 重新加载当前患者的数据,但不清空左侧列表
await loadPatientData(currentSelectedPatient)
// 同步后自动处理BMI和血压值
processAutoFields()
loading.close()
ElMessage.success(`同步成功`)
} catch (error) {
loading.close()
console.error('同步数据失败:', error)
ElMessage.error(error.message || '同步数据失败,请稍后重试')
}
} catch (error) {
console.error('同步失败:', error)
ElMessage.error(error.message || '同步失败,请稍后重试')
}
}
// 添加一个函数处理BMI和血压值同步完成后调用
const processAutoFields = () => {
if (!selectedPatient.value?.medicalSn) return
// 获取当前所有检查项目
const allItems = Object.values(examItems.value).flat()
// 处理BMI项目
const bmiItem = allItems.find(item =>
item.name && item.name.includes('体质指数') && item.name.includes('BMI') &&
item.value
)
if (bmiItem) {
console.log('处理BMI值...')
handleBmiResult(bmiItem)
}
// 处理血压项目
const bpItem = allItems.find(item =>
item.name && item.name.includes('血压') &&
item.value
)
if (bpItem) {
console.log('处理血压值...')
handleBloodPressureResult(bpItem)
}
}
const handleRefresh = async (e) => {
// 阻止默认行为,防止触发浏览器刷新
if (e) e.preventDefault()
try {
const loading = ElLoading.service({
lock: true,
text: '刷新中...',
background: 'rgba(255, 255, 255, 0.7)'
})
// 清除选中状态和右侧内容
selectedPatient.value = null // 清除选中患者
reportData.value = {} // 清空报告数据
examItems.value = {} // 清空检查项目
conclusionData.value = {
// 重置小结数据
general: { summary: '未见异常' },
ultrasound: { finding: '未见异常', diagnosis: '未见异常' },
ecg: { finding: '详见报告单', diagnosis: '详见报告单' },
blood: { summary: '' },
urine: { summary: '未见异常' },
biochemical: { summary: '' }
}
// 清空搜索栏和日期范围
searchQuery.value = ''
dateRange.value = []
// 重置状态筛选
statusFilter.value = '0'
// 刷新患者列表
await getPatientList()
//重置标签
currentTab.value = 'general'
loading.close()
ElMessage.success('刷新成功')
} catch (error) {
console.error('刷新失败:', error)
ElMessage.error('刷新失败,请稍后重试')
}
}
// 添加一个新方法,用于检查患者是否已有检查项目
const checkPatientHasItems = async (medicalSn) => {
try {
const existingItems = await PatientitemsApi.getPatientitemsPage({
medicalSn: medicalSn,
pageNo: 1,
pageSize: 1
})
return existingItems.list && existingItems.list.length > 0
} catch (error) {
console.error('检查患者检查项目失败:', error)
return false
}
}
// 修改结果变化处理函数
const handleResultChange = (item) => {
if (!checkEditPermission()) {
// 如果没有编辑权限,恢复原值
item.value = item.originalValue || ''
return
}
// 如果有输入值,设置为已检状态
if (item.value) {
item.itemStatus = '1'
} else {
item.itemStatus = '0'
}
item.originalValue = item.value
// 对体质指数(BMI)进行特殊处理
if (item.name && item.name.includes('体质指数') && item.name.includes('BMI')) {
handleBmiResult(item)
return
}
// 对血压进行特殊处理
if (item.name && item.name.includes('血压')) {
handleBloodPressureResult(item)
return
}
if (item.reference && item.reference !== 'null-null') {
const value = parseFloat(item.value)
const [low, high] = item.reference
.split('-')
.map((val) => (val === 'null' ? null : Number(val)))
if (low !== null && high !== null) {
item.note = getStatusNote({ itemResult: value, lowValue: low, highValue: high })
item.risk = getRiskLevel({ itemResult: value, lowValue: low, highValue: high })
item.status = getRowStatus({ itemResult: value, lowValue: low, highValue: high })
}
}
}
// 修改操作处理函数
const handleOperation = ({ type, item }) => {
if (!checkEditPermission()) return
switch (type) {
case 'positive':
item.positive = '阳性'
item.itemStatus = '1'
break
case 'negative':
item.positive = '阴性'
item.itemStatus = '1'
break
case 'abandon':
if (item.itemStatus === '2') {
item.itemStatus = '0'
ElMessage.success('已恢复正常状态')
} else {
ElMessageBox.confirm('确定要弃检该项目吗?弃检后将无法编辑该项目。', '警告', {
confirmButtonText: '确定',
cancelButtonText: '取消',
type: 'warning'
})
.then(() => {
item.itemStatus = '2'
ElMessage.success('已设置为弃检')
})
.catch(() => {
ElMessage.info('已取消弃检')
})
}
break
}
}
// 修改禁用状态的计算属性
const isDisabled = computed(() => {
// 如果患者状态为已检查,则禁用
if (selectedPatient.value?.status === '1' || selectedPatient.value?.status === 1) return true
// 检查当前科室的检查项目是否全部完成
const currentDeptItems = Object.values(examItems.value)
.flat()
.filter((item) => item.sectionID === user.value?.deptId)
if (currentDeptItems.length > 0 && currentDeptItems.every((item) => item.itemStatus === '1')) {
return true
}
return false
})
// 修改只读状态的计算属性
const isReadOnly = computed(() => {
// 如果整体已禁用,则为只读
if (isDisabled.value) return true
// 检查当前标签页的检查项目是否全部弃检
const currentItems = examItems.value[currentTab.value] || []
if (currentItems.length > 0 && currentItems.every(item => item.itemStatus === '2')) {
return true // 所有项目都已弃检,设为只读
}
return false
})
// 修改分页处理函数
const handleCurrentChange = async (val) => {
pageNo.value = val
try {
loading.value = true
const params = {
pageNo: pageNo.value,
pageSize: pageSize.value
}
// 简化参数处理
if (statusFilter.value === '2') {
params.isprint = 1
if (dateRange.value?.length === 2) {
params.printTimeRange = [
`${dateRange.value[0]} 00:00:00`,
`${dateRange.value[1]} 23:59:59`
]
}
} else {
params.status = statusFilter.value
}
// 如果是已检查状态或已打印状态,且有机构编码,添加机构编码查询
if ((statusFilter.value === '1' || statusFilter.value === '2') && examhosInfo.value.examhoscode) {
params.examhoscode = examhosInfo.value.examhoscode
}
// 检查缓存
const cacheKey = JSON.stringify(params)
if (patientDataCache.value.has(cacheKey)) {
const cachedData = patientDataCache.value.get(cacheKey)
patients.value = cachedData.list
total.value = cachedData.total
loading.value = false
return
}
const res = await PatientApi.getPatientPage(params)
// 更新缓存
patientDataCache.value.set(cacheKey, res)
// 只更新必要的数据
patients.value = res.list
total.value = res.total
} catch (error) {
console.error('获取患者列表失败:', error)
ElMessage.error('获取患者列表失败')
} finally {
loading.value = false
}
}
// 修改签名加载错误处理
const handleSignatureError = (e) => {
e.target.style.display = 'none'
}
// 添加缓存清理函数
const clearPatientCache = () => {
patientDataCache.value.clear()
}
// 在组件卸载时清理缓存
onBeforeUnmount(() => {
clearPatientCache()
})
// 添加判断是否为影像类检查的计算属性
const isImageExam = computed(() => {
const items = currentExamItems.value || []
return items.some((item) => {
const itemName = (item.name || '').toLowerCase()
return (
itemName.includes('ct') ||
itemName.includes('mri') ||
itemName.includes('超声') ||
itemName.includes('x线') ||
itemName.includes('心电图') ||
itemName.includes('影像') ||
itemName.includes('胸片') ||
itemName.includes('内镜') ||
itemName.includes('放射') ||
itemName.includes('b超') ||
itemName.includes('彩超') ||
itemName.includes('心超')
)
})
})
// 添加检查项目状态的计算属性
const patientExamStatus = computed(() => {
if (!selectedPatient.value?.medicalSn) return '0'
const currentItems = Object.values(examItems.value)
.flat()
.filter((item) => item.sectionID === user.value?.deptId)
if (!currentItems.length) return '0'
const allChecked = currentItems.every((item) => item.itemStatus === '1')
return allChecked ? '1' : '0'
})
// 修改获取状态文本的方法
const getStatusText = (patient) => {
// 直接使用数据库中的 status 字段判断
if (patient.status === '1' || patient.status === 1) {
return '已检查'
}
return '待检查'
}
// 修改状态标签类型
const getStatusTagType = (patient) => {
return getStatusText(patient) === '已检查' ? 'success' : 'info'
}
// 添加参考值格式化函数
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 formatDate = (date) => {
if (!date) return ''
const d = new Date(date)
const year = d.getFullYear()
const month = String(d.getMonth() + 1).padStart(2, '0')
const day = String(d.getDate()).padStart(2, '0')
return `${year}-${month}-${day}`
}
// 修改验证方法,添加对一般检查项目的验证
const validateAllResults = () => {
const errors = []
// 检查超声
if (conclusionData.value.ultrasound) {
if (!conclusionData.value.ultrasound.finding?.trim()) {
errors.push('超声检查所见不能为空')
}
if (!conclusionData.value.ultrasound.diagnosis?.trim()) {
errors.push('超声检查结果不能为空')
}
}
// 检查心电图
if (conclusionData.value.ecg) {
if (!conclusionData.value.ecg.finding?.trim()) {
errors.push('心电图检查所见不能为空')
}
if (!conclusionData.value.ecg.diagnosis?.trim()) {
errors.push('心电图检查结果不能为空')
}
}
// 检查血常规
if (conclusionData.value.blood) {
if (!conclusionData.value.blood.summary?.trim()) {
errors.push('血常规体检小结不能为空')
}
}
// 检查尿常规
if (conclusionData.value.urine) {
if (!conclusionData.value.urine.summary?.trim()) {
errors.push('尿常规体检小结不能为空')
}
}
// 检查生化
if (conclusionData.value.biochemical) {
if (!conclusionData.value.biochemical.summary?.trim()) {
errors.push('生化检查体检小结不能为空')
}
}
// 添加对一般检查项目的验证
if (currentTab.value === 'general') {
const generalItems = sortedExamItems.value || []
// 检查每个一般检查项目是否有值
generalItems.forEach((item, index) => {
// 只验证非弃检的项目
if (item.itemStatus !== '2' && !item.value?.trim()) {
errors.push(`${index + 1}项 "${item.name}" 的检查结果不能为空`)
}
})
}
if (errors.length > 0) {
ElMessage({
message: errors.join('\n'),
type: 'warning',
duration: 5000,
showClose: true,
grouping: true
})
return false
}
return true
}
// 修改统一保存方法,更新检查医生和检查日期,同时更新患者状态和体检日期
const handleSaveAllResults = async () => {
if (!checkEditPermission()) return
// 验证所有标签页的内容(不包含汇总页)
if (!validateAllResults()) return
// 检查是否选择了医生
if (!inspectDoctor.value) {
ElMessage.warning('请选择检查医生')
return
}
// 验证总检医生是否已选择
if (!summaryRef.value?.validateSummaryDoctor()) {
ElMessage.warning('请选择总检医生')
return
}
try {
const userProfile = await getUserProfile()
user.value = userProfile
const currentTimestamp = Date.now()
const currentDate = formatDate(new Date())
// 获取选择的医生信息
let doctorName = inspectDoctor.value
if (doctorName && doctorName.includes('|')) {
doctorName = doctorName.split('|')[1] // 修改为取医生姓名部分而不是ID
}
// 收集所有标签页的所有检查项目
let allUpdatedItems = []
// 遍历所有检查项目
Object.keys(examItems.value).forEach((tabKey) => {
const items = examItems.value[tabKey] || []
items.forEach((item) => {
const itemName = (item.name || '').toLowerCase()
// 基础字段
const baseFields = {
id: item.id,
medicalSn: selectedPatient.value?.medicalSn,
itemStatus: '1', // 设置为已检查状态
inspectdoctor: doctorName || user.value?.nickname || '',
inspecttime: currentTimestamp, // 使用当前时间戳
sectionID: user.value?.deptId,
itemResult: item.value || '' // 添加检查结果值
}
// 根据项目类型处理不同的字段
if (itemName.includes('超声') || itemName.includes('彩超') || itemName.includes('b超')) {
const finding = conclusionData.value.ultrasound?.finding?.trim() || ''
const diagnosis = conclusionData.value.ultrasound?.diagnosis?.trim() || ''
// 拼接成指定格式的字符串保存到analyse字段
const analyseContent = `检查所见:${finding}\n检查结果${diagnosis}`
allUpdatedItems.push({
...baseFields,
examDescription: finding,
itemResult: diagnosis,
analyse: analyseContent
})
} else if (
itemName.includes('心电图') ||
itemName.includes('ecg') ||
itemName.includes('ekg')
) {
const finding = conclusionData.value.ecg?.finding?.trim() || ''
const diagnosis = conclusionData.value.ecg?.diagnosis?.trim() || ''
// 拼接成指定格式的字符串保存到analyse字段
const analyseContent = `检查所见:${finding}\n检查结果${diagnosis}`
allUpdatedItems.push({
...baseFields,
examDescription: finding,
itemResult: diagnosis,
analyse: analyseContent
})
} else if (
itemName.includes('血常规') ||
itemName.includes('血细胞') ||
itemName.includes('血红蛋白')
) {
allUpdatedItems.push({
...baseFields,
analyse: conclusionData.value.blood?.summary?.trim() || '', // 只将小结保存到analyse字段
itemResult: item.value || '' // 保留原始检查结果值
})
} else if (itemName.includes('尿常规') || itemName.includes('尿液分析')) {
allUpdatedItems.push({
...baseFields,
analyse: conclusionData.value.urine?.summary?.trim() || '', // 只将小结保存到analyse字段
itemResult: item.value || '' // 保留原始检查结果值
})
} else if (
itemName.includes('生化') ||
itemName.includes('肝功能') ||
itemName.includes('肾功能') ||
itemName.includes('血脂') ||
itemName.includes('血糖') ||
itemName.includes('电解质')
) {
allUpdatedItems.push({
...baseFields,
analyse: conclusionData.value.biochemical?.summary?.trim() || '', // 只将小结保存到analyse字段
itemResult: item.value || '' // 保留原始检查结果值
})
} else {
// 一般检查项目
allUpdatedItems.push({
...baseFields,
analyse: conclusionData.value.general?.summary?.trim() || '' // 只将小结保存到analyse字段
})
}
})
})
if (allUpdatedItems.length === 0) {
ElMessage.warning('没有需要保存的检查项目')
return
}
// 批量更新所有检查项目
await PatientitemsApi.updatePatientitemsBatch(allUpdatedItems)
// 更新检查医生和检查日期
inspectTime.value = currentDate
// 更新患者状态为已检查 - 调用更新患者状态的API
if (selectedPatient.value) {
// 更新数据库中的status字段为1同时更新体检日期为当前时间戳
await PatientApi.updatePatient({
id: selectedPatient.value.id,
status: 1, // 设置为已检查状态
})
// 更新本地状态
selectedPatient.value.status = 1
selectedPatient.value.medicalDateTime = currentTimestamp
// 更新列表中的患者状态
const patientIndex = patients.value.findIndex((p) => p.id === selectedPatient.value.id)
if (patientIndex !== -1) {
patients.value[patientIndex].status = 1
patients.value[patientIndex].medicalDateTime = currentTimestamp
}
// 更新过滤后的列表中的患者状态
const filteredIndex = filteredPatients.value.findIndex(
(p) => p.id === selectedPatient.value.id
)
if (filteredIndex !== -1) {
filteredPatients.value[filteredIndex].status = 1
filteredPatients.value[filteredIndex].medicalDateTime = currentTimestamp
}
}
// 最后执行汇总保存
const result = await handleSummarySave()
if (!result) return
ElMessage.success('所有检查结果保存成功')
await PatientApi.generateReport(selectedPatient.value?.medicalSn)
// 体检报告信息回传
PatientApi.PushJYPatientInfo(selectedPatient.value?.medicalSn)
// 重新加载数据以更新界面
await refreshExamData()
} catch (error) {
ElMessage.error(`保存失败: ${error.message || '请检查数据是否完整'}`)
}
}
// 修改汇总保存方法
const handleSummarySave = async () => {
try {
// 检查summaryRef是否存在
if (summaryRef.value) {
// 如果在汇总标签页,直接调用组件方法
await summaryRef.value.saveSummary()
return true
} else {
// 如果不在汇总标签页,需要手动构建汇总内容并保存
// 格式化汇总数据
let summaryContent = ''
// 一般检查
if (conclusionData.value.general?.summary) {
summaryContent += '【一般检查】\n' + conclusionData.value.general.summary + '\n\n'
}
// 超声检查
if (conclusionData.value.ultrasound?.finding || conclusionData.value.ultrasound?.diagnosis) {
summaryContent += '【超声】\n'
if (conclusionData.value.ultrasound.finding) {
summaryContent += '检查所见:' + conclusionData.value.ultrasound.finding + '\n'
}
if (conclusionData.value.ultrasound.diagnosis) {
summaryContent += '检查结果:' + conclusionData.value.ultrasound.diagnosis + '\n'
}
summaryContent += '\n'
}
// 心电图检查
if (conclusionData.value.ecg?.finding || conclusionData.value.ecg?.diagnosis) {
summaryContent += '【心电图】\n'
if (conclusionData.value.ecg.finding) {
summaryContent += '检查所见:' + conclusionData.value.ecg.finding + '\n'
}
if (conclusionData.value.ecg.diagnosis) {
summaryContent += '检查结果:' + conclusionData.value.ecg.diagnosis + '\n'
}
summaryContent += '\n'
}
// 血常规
if (conclusionData.value.blood?.summary) {
summaryContent += '【血常规】\n' + conclusionData.value.blood.summary + '\n\n'
}
// 尿常规
if (conclusionData.value.urine?.summary) {
summaryContent += '【尿常规】\n' + conclusionData.value.urine.summary + '\n\n'
}
// 生化
if (conclusionData.value.biochemical?.summary) {
summaryContent += '【生化】\n' + conclusionData.value.biochemical.summary + '\n\n'
}
// 如果有汇总内容,则保存
if (summaryContent.trim()) {
// 准备保存的数据
const saveData = {
medicalSn: selectedPatient.value?.medicalSn,
summaryResult: summaryContent
}
// 调用API保存数据
await PatientApi.updatemedicalSn(saveData)
return true
}
return true // 即使没有内容也返回成功
}
} catch (error) {
console.error('汇总保存失败:', error)
ElMessage.error('汇总保存失败: ' + error.message)
return false
}
}
// 修改 refreshExamData 函数,确保正确更新检查状态和医生信息
const refreshExamData = async () => {
try {
// 重新获取患者信息以更新状态
if (selectedPatient.value) {
const updatedPatient = await PatientApi.getPatient(selectedPatient.value.id)
if (updatedPatient) {
// 更新选中患者的状态
selectedPatient.value = updatedPatient
// 更新列表中的患者状态
const patientIndex = patients.value.findIndex((p) => p.id === selectedPatient.value.id)
if (patientIndex !== -1) {
patients.value[patientIndex] = updatedPatient
}
// 更新过滤后的列表中的患者状态
const filteredIndex = filteredPatients.value.findIndex(
(p) => p.id === selectedPatient.value.id
)
if (filteredIndex !== -1) {
filteredPatients.value[filteredIndex] = updatedPatient
}
}
}
// 获取检查项目数据
const params = {
medicalSn: selectedPatient.value?.medicalSn,
pageNo: 1,
pageSize: 100
}
const itemsRes = await PatientitemsApi.getPatientitemsPage(params)
if (itemsRes.list && itemsRes.list.length > 0) {
// 查找已检查的项目,获取检查医生
const checkedItems = itemsRes.list.filter(
(item) => item.itemStatus === '1' && item.sectionID === user.value.deptId
)
if (checkedItems.length > 0) {
// 使用第一个已检查项目的检查医生
const firstCheckedItem = checkedItems[0]
// 设置检查医生
if (firstCheckedItem.inspectdoctor) {
inspectDoctor.value = firstCheckedItem.inspectdoctor
// 更新检查状态为已完成,这样就不会显示选择控件
isExamCompleted.value = true
}
// 格式化检查时间
if (firstCheckedItem.inspecttime) {
const inspectDate = new Date(Number(firstCheckedItem.inspecttime))
inspectTime.value = formatDate(inspectDate)
}
}
}
} catch (error) {
console.error('刷新数据失败:', error)
}
}
// 添加检查医生和检查日期的响应式引用
const inspectDoctor = ref('')
const inspectTime = ref('')
// 不再需要 inspectDate 变量,直接使用当前日期
// 修改特殊检查类型的计算属性移除summary
const isSpecialExam = computed(() => {
return ['ultrasound', 'ecg', 'blood', 'urine', 'biochemical'].includes(currentTab.value)
})
// 添加状态筛选的响应式引用
const statusFilter = ref('0') // 默认选择待检查
// 修改过滤后的患者列表计算属性
const filteredPatients = computed(() => {
// 直接返回API获取的患者列表不再进行二次过滤
// 由于API请求时已经传递了status参数进行过滤
return patients.value
})
// 添加加载状态
const loading = ref(false)
// 添加防抖处理的状态切换函数
const debouncedStatusChange = debounce(async (value) => {
try {
loading.value = true
const params = {
pageNo: 1, // 重置为第一页
pageSize: pageSize.value,
isprint: null
}
// 根据不同的状态值设置不同的查询参数
if (value === '2') {
params.isprint = 1
} else {
params.status = value
}
// 如果是已检查状态或已打印状态,且有机构编码,则添加机构编码查询
if ((value === '1' || value === '2') && examhosInfo.value.examhoscode) {
params.examhoscode = examhosInfo.value.examhoscode
}
// 添加超时处理
const timeoutPromise = new Promise((_, reject) => {
setTimeout(() => reject(new Error('请求超时')), 10000) // 10秒超时
})
const fetchPromise = PatientApi.getPatientPage(params)
const res = await Promise.race([fetchPromise, timeoutPromise])
patients.value = res.list
total.value = res.total
selectedPatient.value = null
searchQuery.value = ''
dateRange.value = []
} catch (error) {
console.error('获取患者列表失败:', error)
if (error.message === '请求超时') {
ElMessage.error('请求超时,请稍后重试')
} else {
ElMessage.error('获取患者列表失败')
}
} finally {
loading.value = false
}
}, 300) // 300ms的防抖延迟
// 修改状态筛选变化处理函数
const handleStatusFilterChange = (value) => {
statusFilter.value = value
pageNo.value = 1
if (value === '2') {
// 使用防抖处理日期范围设置
const debouncedDateChange = debounce(() => {
if (!dateRange.value?.length) {
const today = new Date().toISOString().split('T')[0]
dateRange.value = [today, today]
}
handleDateRangeChange(dateRange.value)
}, 300)
debouncedDateChange()
} else {
dateRange.value = []
debouncedStatusChange(value)
}
}
// 添加检查是否已完成的响应式引用
const isExamCompleted = ref(false)
// 添加计算属性处理小结内容
const currentSummary = computed({
get() {
if (conclusionData.value[currentTab.value]?.summary) {
return conclusionData.value[currentTab.value].summary
} else if (typeof conclusionData.value[currentTab.value] === 'string') {
return conclusionData.value[currentTab.value]
}
return ''
},
set(value) {
if (typeof conclusionData.value[currentTab.value] === 'object') {
conclusionData.value[currentTab.value].summary = value
} else {
conclusionData.value[currentTab.value] = value
}
}
})
// 添加模板相关的状态
const drawerVisible = ref(false)
const currentTemplateType = ref('')
// 修改打开模板抽屉的函数,添加字段参数
const openTemplateDrawer = (type, field = 'finding') => {
if (isReadOnly.value) {
ElMessage.warning('已检查患者不可修改内容')
return
}
// 保存当前字段类型到一个新的响应式引用
currentTemplateField.value = field
// 根据当前标签页设置对应的模板类型
let templateType
switch (currentTab.value) {
case 'general':
templateType = '一般检查'
break
case 'ultrasound':
templateType = '超声'
break
case 'ecg':
templateType = '心电图'
break
case 'blood':
templateType = '血常规'
break
case 'urine':
templateType = '尿常规'
break
case 'biochemical':
templateType = '生化'
break
case 'summary':
templateType = '汇总'
break
default:
templateType = '通用'
}
currentTemplateType.value = templateType
drawerVisible.value = true
}
// 添加当前选择的字段类型
const currentTemplateField = ref('finding')
// 插入选中的模板内容
const insertTemplate = (templateContent) => {
if (isReadOnly.value) return
switch (currentTab.value) {
case 'ultrasound':
if (currentTemplateField.value === 'diagnosis') {
conclusionData.value.ultrasound.diagnosis += templateContent
} else {
conclusionData.value.ultrasound.finding += templateContent
}
break
case 'ecg':
if (currentTemplateField.value === 'diagnosis') {
conclusionData.value.ecg.diagnosis += templateContent
} else {
conclusionData.value.ecg.finding += templateContent
}
break
case 'blood':
case 'urine':
case 'biochemical':
case 'general':
conclusionData.value[currentTab.value].summary += templateContent
break
case 'summary':
summaryRef.value?.insertTemplate(templateContent)
break
}
drawerVisible.value = false
}
// 添加保存当前标签页小结的方法
const handleSaveCurrentTab = async () => {
if (!checkEditPermission()) return
try {
const loading = ElLoading.service({
lock: true,
text: '保存中...',
background: 'rgba(255, 255, 255, 0.7)'
})
const currentTimestamp = Date.now()
// 获取当前标签页的检查项目
const currentItems = examItems.value[currentTab.value] || []
if (currentItems.length === 0) {
ElMessage.warning('当前标签页没有检查项目')
loading.close()
return
}
// 准备更新的数据
const updatedItems = currentItems.map((item) => {
const baseFields = {
id: item.id,
medicalSn: selectedPatient.value?.medicalSn,
itemStatus: '1', // 设置为已检查状态
itemResult: item.value || ''
}
// 根据当前标签页类型处理不同的字段
if (currentTab.value === 'ultrasound' || currentTab.value === 'ecg') {
const finding = conclusionData.value[currentTab.value]?.finding?.trim() || ''
const diagnosis = conclusionData.value[currentTab.value]?.diagnosis?.trim() || ''
return {
...baseFields,
examDescription: finding,
itemResult: diagnosis
}
} else {
// 其他类型的检查项目
return {
...baseFields,
analyse: conclusionData.value[currentTab.value]?.summary?.trim() || ''
}
}
})
// 根据不同标签页类型保存体检小结
if (currentTab.value === 'blood') {
await PacsDataApi.updatePacsDataitem({
code: selectedPatient.value?.medicalSn,
type: 'cbc',
item: updatedItems[0].analyse
})
} else if (currentTab.value === 'urine') {
await PacsDataApi.updatePacsDataitem({
code: selectedPatient.value?.medicalSn,
type: 'urine',
item: updatedItems[0].analyse
})
} else if (currentTab.value === 'biochemical') {
await PacsDataApi.updatePacsDataitem({
code: selectedPatient.value?.medicalSn,
type: 'bt',
item: updatedItems[0].analyse
})
}
// 批量更新检查项目
await PatientitemsApi.updatePatientitemsBatch(updatedItems)
loading.close()
ElMessage.success('保存成功')
// 刷新数据
await refreshExamData()
} catch (error) {
console.error('保存失败:', error)
ElMessage.error(`保存失败: ${error.message || '请检查数据是否完整'}`)
}
}
const handleAbandonExam = async () => {
if (!checkEditPermission()) return
try {
// 确认是否要弃检
await ElMessageBox.confirm('确定要弃检当前项目吗?弃检后将无法编辑。', '弃检确认', {
confirmButtonText: '确定弃检',
cancelButtonText: '取消',
type: 'warning'
})
const loading = ElLoading.service({
lock: true,
text: '处理中...',
background: 'rgba(255, 255, 255, 0.7)'
})
try {
// 获取当前标签页的检查项目
const currentItems = examItems.value[currentTab.value] || []
if (currentItems.length === 0) {
ElMessage.warning('当前标签页没有检查项目')
loading.close()
return
}
// 准备更新的数据
const updatedItems = currentItems.map(item => {
const baseFields = {
id: item.id,
medicalSn: selectedPatient.value?.medicalSn,
itemStatus: '2' // 设置为弃检状态
}
// 根据当前标签页类型添加不同的弃检信息
if (currentTab.value === 'ultrasound' || currentTab.value === 'ecg') {
return {
...baseFields,
examDescription: '已弃检',
itemResult: '已弃检',
analyse: '检查所见:已弃检\n检查结果已弃检'
}
} else {
return {
...baseFields,
analyse: '该项目已弃检'
}
}
})
// 批量更新检查项目
await PatientitemsApi.updatePatientitemsBatch(updatedItems)
// 更新本地检查项目状态
currentItems.forEach(item => {
item.itemStatus = '2'
if (currentTab.value === 'ultrasound' || currentTab.value === 'ecg') {
item.value = '已弃检'
// 同时更新小结数据
if (currentTab.value === 'ultrasound') {
conclusionData.value.ultrasound.finding = '已弃检'
conclusionData.value.ultrasound.diagnosis = '已弃检'
} else if (currentTab.value === 'ecg') {
conclusionData.value.ecg.finding = '已弃检'
conclusionData.value.ecg.diagnosis = '已弃检'
}
} else {
item.analyse = '该项目已弃检'
}
})
loading.close()
ElMessage.success('弃检成功')
// 刷新数据
await refreshExamData()
} catch (error) {
loading.close()
console.error('弃检失败:', error)
ElMessage.error(`弃检失败: ${error.message || '请稍后重试'}`)
}
} catch {
// 用户取消弃检
ElMessage.info('已取消弃检')
}
}
// 添加医生列表的响应式引用
const doctorList = ref([])
// 修改获取医生列表的方法
const getDoctorList = async () => {
try {
const res = await DoctorApi.getDoctorPage({
pageNo: 1,
pageSize: 100, // 设置较大的数值以获取所有医生
orgid: user.value?.deptId
})
if (res && res.list && res.list.length > 0) {
// 保存原始医生列表数据
doctorList.value = res.list.map(doctor => ({
label: doctor.doctorname,
value: `${doctor.doctorid}|${doctor.doctorname}`
}))
// 如果已经获取到了用户信息,尝试匹配医生
if (user.value?.nickname) {
// 使用精确匹配
const matchedDoctor = res.list.find(doctor =>
doctor.doctorname === user.value.nickname
)
if (matchedDoctor) {
// 设置检查医生
inspectDoctor.value = `${matchedDoctor.doctorid}|${matchedDoctor.doctorname}`
console.log('已为检查医生设置默认值:', inspectDoctor.value)
} else {
console.log('未找到与用户昵称匹配的医生:', user.value.nickname)
}
} else {
console.log('未获取到用户昵称')
}
}
} catch (error) {
console.error('获取医生列表失败:', error)
ElMessage.error('获取医生列表失败')
}
}
// 添加日期范围选择相关的响应式引用
const dateRange = ref([])
// 添加日期范围变化处理函数
const handleDateRangeChange = async (val) => {
try {
loading.value = true
// 重置页码为1
pageNo.value = 1
const params = {
pageNo: pageNo.value,
pageSize: pageSize.value,
isprint: 1 // 保持已打印状态
}
// 如果有机构编码,添加到查询条件
if (examhosInfo.value.examhoscode) {
params.examhoscode = examhosInfo.value.examhoscode
}
// 只有在有日期范围时才添加日期条件
if (val && val.length === 2) {
params.printTimeRange = [
`${val[0]} 00:00:00`,
`${val[1]} 23:59:59`
]
}
// 检查缓存
const cacheKey = JSON.stringify(params)
if (patientDataCache.value.has(cacheKey)) {
const cachedData = patientDataCache.value.get(cacheKey)
patients.value = cachedData.list
total.value = cachedData.total
loading.value = false
return
}
const res = await PatientApi.getPatientPage(params)
// 更新缓存
patientDataCache.value.set(cacheKey, res)
patients.value = res.list
total.value = res.total
} catch (error) {
console.error('按日期获取患者列表失败:', error)
ElMessage.error('获取患者列表失败')
} finally {
loading.value = false
}
}
// 添加重置患者状态的方法
const resetPatientStatus = async (patient) => {
try {
// 确认是否要重置状态
await ElMessageBox.confirm('确定要重置该患者的状态吗?重置后将无法恢复。', '重置状态确认', {
confirmButtonText: '确定',
cancelButtonText: '取消',
type: 'warning'
})
const loading = ElLoading.service({
lock: true,
text: '处理中...',
background: 'rgba(255, 255, 255, 0.7)'
})
try {
// 更新数据库中的status字段为0同时更新体检日期为当前时间戳
await PatientApi.updatePatient({
id: patient.id,
status: 0, // 设置为待检查状态
})
// 更新本地状态
patient.status = 0
patient.medicalDateTime = Date.now()
// 更新列表中的患者状态
const patientIndex = patients.value.findIndex((p) => p.id === patient.id)
if (patientIndex !== -1) {
patients.value[patientIndex].status = 0
patients.value[patientIndex].medicalDateTime = Date.now()
}
// 更新过滤后的列表中的患者状态
const filteredIndex = filteredPatients.value.findIndex(
(p) => p.id === patient.id
)
if (filteredIndex !== -1) {
filteredPatients.value[filteredIndex].status = 0
filteredPatients.value[filteredIndex].medicalDateTime = Date.now()
}
loading.close()
ElMessage.success('状态重置成功')
// 刷新数据
await refreshExamData()
} catch (error) {
loading.close()
console.error('重置状态失败:', error)
ElMessage.error('重置状态失败,请稍后重试')
}
} catch {
// 用户取消重置状态
ElMessage.info('已取消重置状态')
}
}
// 添加一个函数用于截断体检编号,如果空间不足
const truncateMedicalSn = (sn) => {
if (!sn) return '';
// 如果编号长度超过10个字符则截断并添加省略号
return sn.length > 10 ? sn.substring(0, 8) + '...' : sn;
}
// 在组件卸载时清理缓存
onBeforeUnmount(() => {
clearPatientCache()
})
// 状态映射配置
const STATUS_MAP = {
0: { text: '待检查', color: 'info', showButton: false },
1: { text: '已检查', color: 'success', showButton: true },
}
// 统一获取状态信息的方法
const getStatusInfo = (patient) => {
return STATUS_MAP[patient.status] || { text: '未知状态', color: 'info', showButton: false }
}
// 添加体检机构信息的响应式引用
const examhosInfo = ref({
examhoscode: '',
examhosname: ''
})
</script>
<style scoped>
.medical-report {
display: flex;
height: calc(100vh - 120px); /* 使用视口高度减去头部和其他元素的高度 */
min-height: 600px;
overflow: hidden;
width: 100%;
}
.patient-list {
width: 280px;
min-width: 250px; /* 设置最小宽度 */
background: #fff;
border-right: 1px solid #e6e6e6;
display: flex;
flex-direction: column; /* 确保子元素垂直排列 */
height: 100%;
}
.list-header {
padding: 0;
}
.header-title {
font-size: 14px;
background: #fff;
border-bottom: 1px solid #fff;
color: #333;
display: flex;
align-items: center;
justify-content: space-between;
width: 100%;
padding: 8px 0;
}
.filter-options {
width: 100%;
padding: 0 10px;
}
.radio-label {
margin-right: 20px;
cursor: pointer;
font-size: 14px;
color: #606266;
}
.radio-label input[type='radio'] {
margin-right: 4px;
vertical-align: middle;
}
.view-options {
padding: 10px 15px;
display: flex;
flex-direction: column;
border-bottom: 1px solid #e6e6e6;
}
.view-buttons {
display: flex;
gap: 8px;
}
.view-btn {
padding: 5px 12px;
border: none;
background: none;
cursor: pointer;
font-size: 13px;
color: #606266;
border-radius: 3px;
}
.view-btn:hover {
color: #409eff;
background: #ecf5ff;
}
.view-btn.active {
color: #409eff;
background: #ecf5ff;
}
.search-box {
padding: 10px 15px;
position: relative;
border-bottom: 1px solid #e6e6e6;
}
.search-box input {
width: 100%;
padding: 8px 30px 8px 10px;
border: 1px solid #dcdfe6;
border-radius: 4px;
font-size: 13px;
}
.search-box input:focus {
border-color: #409eff;
outline: none;
}
.search-icon {
position: absolute;
right: 25px;
top: 50%;
transform: translateY(-50%);
color: #c0c4cc;
}
.patient-item {
display: flex;
justify-content: space-between;
align-items: flex-start;
padding: 12px 15px;
border-bottom: 1px solid #e6e6e6;
cursor: pointer;
}
.patient-item:hover {
background-color: #f5f7fa;
}
.patient-item.active {
background-color: #ecf5ff;
}
.patient-item .name {
font-weight: bold;
font-size: 14px;
color: #303133;
}
.patient-item .medical-sn {
font-size: 12px;
color: #909399;
}
.patient-item .card-id {
font-size: 12px;
color: #909399;
display: block;
margin-top: 3px;
}
.status-tag {
font-size: 12px;
}
.report-content {
flex: 1;
display: flex;
flex-direction: column;
position: relative;
background: #fff;
overflow: auto; /* 添加滚动条 */
height: 100%;
}
.main-content {
flex: 1;
overflow-y: auto;
padding: 20px;
padding-bottom: 60px;
}
.progress-nav {
display: flex;
margin-bottom: 20px;
position: relative;
}
.nav-item {
position: relative;
padding: 8px 40px;
background: #e4e7ed;
color: #606266;
font-size: 14px;
cursor: pointer;
display: flex;
align-items: center;
margin-right: 4px;
}
.nav-item:after {
content: '';
position: absolute;
right: -20px;
top: 0;
border-left: 20px solid #e4e7ed;
border-top: 18px solid transparent;
border-bottom: 18px solid transparent;
z-index: 1;
}
.nav-item.active {
background: #409eff;
color: white;
}
.nav-item.active:after {
border-left-color: #409eff;
}
.basic-info {
padding: 10px;
background: #f8f9fa;
border-radius: 4px;
flex-shrink: 0; /* 防止基本信息区域被压缩 */
}
.photo-box {
width: 120px;
height: 160px;
background: #fff;
border: 1px dashed #dcdfe6;
display: flex;
align-items: center;
justify-content: center;
}
.no-photo {
color: #909399;
font-size: 14px;
}
.photo {
width: 100%;
height: 100%;
object-fit: cover;
}
.info-grid {
flex: 1;
}
.info-row {
display: flex;
justify-content: space-between;
align-items: center;
margin-bottom: 5px;
}
.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;
}
.info-item span {
color: #333;
flex: 1;
overflow: hidden;
text-overflow: ellipsis;
white-space: nowrap;
}
.full-width {
width: 100%;
}
.full-width .info-item {
flex: none;
width: 100%;
}
.full-width .info-item span {
flex: 1;
}
.exam-tabs {
display: flex;
gap: 10px; /* 添加间隔 */
margin-bottom: 15px;
padding: 10px 0;
}
.tab-item {
position: relative;
padding: 8px 16px;
cursor: pointer;
display: flex;
align-items: center;
gap: 6px;
border-radius: 4px;
background: #f5f7fa; /* 添加底色 */
color: #606266;
font-size: 14px;
border: 1px solid #dcdfe6; /* 添加边框 */
transition: all 0.3s;
}
.tab-indicator {
width: 10px;
height: 10px;
border-radius: 2px;
}
.tab-item:hover {
background: #ecf5ff;
border-color: #c6e2ff;
}
.tab-item.active {
background: #ecf5ff;
border-color: #409eff;
color: #409eff;
font-weight: 500;
}
.result-table {
flex: 1;
overflow: auto; /* 使表格可滚动 */
border: 1px solid #ebeef5;
border-radius: 4px;
display: flex;
flex-direction: column;
background: #fff;
min-height: 200px; /* 设置最小高度 */
}
/* 表头样式 */
.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;
overflow-x: hidden;
}
.table-row {
display: flex;
border-bottom: 1px solid #ebeef5;
}
.table-cell {
padding: 12px 8px;
border-right: 1px solid #ebeef5;
display: flex;
align-items: center;
}
/* 输入框和下拉框样式 */
.cell-input,
.cell-select {
width: 100%;
border: none;
background: transparent;
outline: none;
padding: 0;
}
/* 警告和危险行样式 */
.danger-row {
background: #fc00262d;
}
/* 美化滚动条 */
.table-body::-webkit-scrollbar {
width: 6px;
height: 6px;
}
.table-body::-webkit-scrollbar-thumb {
background: #c0c4cc;
border-radius: 3px;
}
.table-body::-webkit-scrollbar-track {
background: #f5f7fa;
}
/* 修改体检小结样式 */
.summary-section {
margin-top: 15px;
padding: 15px;
background: #f8f9fa;
border-radius: 4px;
flex-shrink: 0; /* 防止被压缩 */
}
.section-title {
font-size: 16px;
font-weight: 500;
color: #303133;
margin-bottom: 15px;
padding-left: 10px;
border-left: 4px solid #409eff;
}
.summary-textarea {
width: 100%;
height: 100px; /* 减小高度 */
padding: 12px;
border: 1px solid #dcdfe6;
border-radius: 4px;
resize: none;
font-size: 14px;
line-height: 1.5;
background: #fff;
}
.summary-textarea:focus {
outline: none;
border-color: #409eff;
}
.summary-textarea[readonly] {
background-color: #f5f7fa;
cursor: not-allowed;
}
.action-footer {
position: sticky; /* 改为粘性定位 */
bottom: 0;
left: 0;
right: 0;
display: flex;
justify-content: space-between;
align-items: center;
padding: 10px 20px;
background: #fff;
border-top: 1px solid #ebeef5;
z-index: 10;
flex-shrink: 0; /* 防止被压缩 */
}
.left-section {
display: flex;
align-items: center;
gap: 20px;
flex-wrap: nowrap; /* 防止换行 */
}
.signature {
height: 30px;
margin: 0 10px;
object-fit: contain;
}
.right-section {
display: flex;
gap: 10px;
}
.action-btn {
padding: 6px 16px;
border: none;
border-radius: 4px;
background: #40b6ff;
color: white;
cursor: pointer;
font-size: 14px;
transition: all 0.3s;
}
.action-btn:hover {
opacity: 0.9;
}
.action-btn.primary {
background: #40b6ff;
}
.action-buttons {
display: flex;
gap: 15px;
}
.dialog-footer {
display: flex;
justify-content: flex-end;
margin-top: 20px;
gap: 10px;
}
.date-picker-container {
margin-top: 10px;
background: #fff;
padding: 10px 0;
width: 100%;
}
.date-picker-wrapper {
display: flex;
gap: 10px;
align-items: center;
margin-bottom: 10px;
}
.search-button {
width: 100%;
margin-top: 8px;
height: 32px;
}
.patient-info {
flex: 1;
display: flex;
flex-direction: column;
width: 100%;
}
.name {
min-width: 64px; /* 预留四个汉字的宽度 */
max-width: 64px;
overflow: hidden;
text-overflow: ellipsis;
white-space: nowrap;
display: inline-block;
}
.medical-sn {
color: #909399;
font-size: 12px;
margin-right: 4px;
flex: 1;
overflow: hidden;
text-overflow: ellipsis;
white-space: nowrap;
}
.status-tag {
margin-left: auto; /* 将状态标签推到右侧 */
font-size: 12px;
flex-shrink: 0; /* 防止标签被压缩 */
}
.list-content {
flex: 1; /* 让列表内容区域占据剩余空间 */
overflow-y: auto;
position: relative;
display: flex;
flex-direction: column;
}
/* 添加空状态样式 */
.empty-content {
flex: 1;
display: flex;
justify-content: center;
align-items: center;
background: #fff;
border-radius: 4px;
}
/* 添加选中状态样式 */
.patient-item.active {
background-color: #ecf5ff;
}
.patient-item:hover {
background-color: #f5f7fa;
cursor: pointer;
}
.result-table td input {
width: 100%;
padding: 4px 8px;
border: none;
background: transparent;
box-sizing: border-box;
}
.result-table td {
padding: 8px;
border: 1px solid #ebeef5;
text-align: left;
min-width: 100px; /* 设置最小宽度 */
}
/* 为明细结果列设置固定宽度 */
.result-table th:nth-child(3),
.result-table td:nth-child(3) {
width: 200px; /* 可以根据需要调整宽度 */
}
/* 修改分页容器样式 */
.pagination-container {
padding: 10px 15px;
text-align: right;
}
/* 自定义分页组件样式 */
:deep(.el-pagination) {
font-size: 12px;
justify-content: flex-start;
width: 100%;
white-space: nowrap; /* 防止内容换行 */
}
:deep(.el-pagination .el-pagination__total) {
margin-right: 8px;
}
:deep(.el-pagination .el-pagination__jump) {
margin-left: 8px;
}
:deep(.el-pagination .el-input__inner) {
height: 24px;
line-height: 24px;
}
:deep(.el-pagination .el-pagination__editor.el-input) {
width: 50px;
}
.no-signature {
color: #909399;
font-size: 14px;
}
/* 添加图片展示区域样式 */
.result-table {
flex: 1;
overflow: auto;
background: #fff;
}
/* 确保图片展示组件能够正确填充空间 */
:deep(.exam-images) {
height: 100%;
width: 100%;
display: flex;
flex-direction: column;
overflow: auto;
}
/* 美化滚动条样式 */
.result-table::-webkit-scrollbar {
width: 6px;
height: 6px;
}
.result-table::-webkit-scrollbar-thumb {
background: #c0c4cc;
border-radius: 3px;
}
.result-table::-webkit-scrollbar-track {
background: #f5f7fa;
}
/* 添加文字按钮样式 */
.text-button {
cursor: pointer;
font-size: 15px;
transition: all 0.3s;
}
.text-button.danger {
color: #f56c6c;
}
.text-button.danger:hover {
color: #f78989;
}
.positive-indicator {
margin-left: 8px;
font-size: 12px;
}
.table-cell {
display: flex;
align-items: center;
gap: 4px;
}
/* 添加下拉菜单相关样式 */
.el-dropdown-link {
cursor: pointer;
color: #409eff;
display: flex;
align-items: center;
font-size: 14px;
}
.el-dropdown-link:hover {
color: #66b1ff;
}
:deep(.el-dropdown-menu__item.is-active) {
color: #409eff;
background-color: #ecf5ff;
}
:deep(.el-dropdown-menu__item--divided) {
margin-top: 6px;
border-top: 1px solid #ebeef5;
}
:deep(.el-dropdown-menu__item--divided:before) {
height: 1px;
margin: 0 -20px;
background-color: #ebeef5;
}
.negative-text {
color: #333;
font-size: 14px;
}
/* 修改下拉按钮样式以匹配 baseUI */
:deep(.el-dropdown) {
margin-right: 8px;
}
:deep(.el-button) {
display: flex;
align-items: center;
justify-content: center;
gap: 4px;
}
/* 添加禁用状态的样式 */
.cell-input:disabled {
background-color: #f5f7fa;
cursor: not-allowed;
color: #606266;
}
/* 修改弃检行的样式判断 */
.table-row[data-item-status='2'] {
background-color: #ebeef5;
color: #606266;
}
/* 修改弃检状态下的下拉菜单样式判断 */
.table-row[data-item-status='2'] .el-dropdown {
opacity: 0.8;
}
/* 固定列样式 */
.fixed-cell {
position: sticky;
background: #fff;
z-index: 1;
}
.table-row .fixed-cell:nth-child(1) {
left: 0;
}
.table-row .fixed-cell:nth-child(2) {
left: 5%;
}
/* 更新搜索框样式 */
.medical-sn-search {
margin-top: 10px;
}
.medical-sn-search input {
width: 100%;
padding: 6px 12px;
border: 1px solid #dcdfe6;
border-radius: 4px;
font-size: 13px;
}
.medical-sn-search input:focus {
border-color: #409eff;
outline: none;
}
.status-tag {
margin-left: 8px;
font-size: 12px;
}
.patient-info {
display: flex;
align-items: center;
gap: 8px;
flex-wrap: wrap;
}
.medical-sn {
color: #909399;
font-size: 12px;
margin-right: 4px;
}
.action-btn:disabled {
background-color: #a0cfff;
cursor: not-allowed;
opacity: 0.7;
}
:deep(.el-dropdown.is-disabled) {
opacity: 0.7;
cursor: not-allowed;
}
:deep(.el-button.is-disabled) {
background-color: #a0cfff;
cursor: not-allowed;
opacity: 0.7;
}
/* 修改只读输入框样式 */
.cell-input[readonly] {
background-color: transparent;
cursor: not-allowed;
}
/* 只读状态的文本框样式 */
.summary-textarea[readonly],
.findings-textarea[readonly],
.diagnosis-textarea[readonly] {
background-color: #f5f7fa;
cursor: not-allowed;
}
.right-content {
flex: 1;
display: flex;
flex-direction: column;
height: 100%;
overflow: hidden;
}
.tabs-container {
flex-shrink: 0;
padding: 10px 15px;
border-bottom: 1px solid #ebeef5;
}
.content-container {
flex: 1;
overflow: auto;
position: relative;
}
.footer-container {
flex-shrink: 0;
padding: 10px 15px;
border-top: 1px solid #ebeef5;
background: #f8f9fa;
}
.no-patient-selected {
display: flex;
justify-content: center;
align-items: center;
height: 100%;
}
.refresh-btn {
padding: 6px;
margin-left: 8px;
}
.refresh-btn:hover {
opacity: 0.8;
}
/* 添加双栏布局相关样式 */
.findings-diagnosis-container {
display: flex;
gap: 20px;
margin-top: 15px;
flex-shrink: 0; /* 防止被压缩 */
}
.findings-section,
.diagnosis-section {
flex: 1;
display: flex;
flex-direction: column;
}
.findings-textarea,
.diagnosis-textarea {
width: 100%;
height: 120px;
padding: 12px;
border: 1px solid #dcdfe6;
border-radius: 4px;
resize: none;
font-size: 14px;
line-height: 1.5;
background: #fff;
}
.findings-textarea:focus,
.diagnosis-textarea:focus {
outline: none;
border-color: #409eff;
}
.findings-textarea[readonly],
.diagnosis-textarea[readonly] {
background-color: #f5f7fa;
cursor: not-allowed;
}
/* 修改按钮样式 */
.header-buttons {
display: flex;
flex-direction: row;
gap: 8px;
align-items: center;
justify-content: flex-end;
}
/* 确保按钮容器有足够的宽度 */
.filter-options {
width: 100%;
}
/* 确保按钮不会换行 */
.header-buttons .el-button {
flex-shrink: 0;
margin-left: 8px;
white-space: nowrap;
}
/* 添加状态筛选样式 */
.status-filter {
padding: 10px 15px;
border-bottom: 1px solid #e6e6e6;
}
:deep(.el-radio-group) {
display: flex;
justify-content: space-around;
width: 100%;
}
:deep(.el-radio) {
margin-right: 0;
}
:deep(.el-radio__label) {
font-size: 13px;
}
/* 添加媒体查询,适应不同屏幕尺寸 */
@media screen and (max-width: 1366px) {
.findings-diagnosis-container {
flex-direction: column;
gap: 10px;
}
.findings-textarea,
.diagnosis-textarea,
.summary-textarea {
height: 80px;
}
.exam-tabs {
flex-wrap: wrap;
}
}
@media screen and (max-width: 1024px) {
.patient-list {
width: 240px;
}
.info-row {
flex-direction: column;
gap: 8px;
}
.info-item {
width: 100%;
}
}
/* 添加这些新样式 */
.doctor-select-container {
display: flex;
align-items: center;
white-space: nowrap;
}
.doctor-select {
margin-left: 8px;
width: 180px;
}
.date-container {
display: flex;
align-items: center;
white-space: nowrap;
}
/* 修改左侧区域样式 */
.left-section {
display: flex;
align-items: center;
gap: 20px;
flex-wrap: nowrap; /* 防止换行 */
}
/* 确保 el-select 不会被挤压 */
:deep(.el-select) {
width: auto;
min-width: 180px;
}
.card-id {
color: #909399;
font-size: 12px;
padding-left: 15px;
overflow: hidden;
text-overflow: ellipsis;
white-space: nowrap;
display: block;
}
.section-title {
display: flex;
align-items: center;
justify-content: space-between;
margin-bottom: 10px;
}
.section-title .el-button {
padding: 0;
font-size: 14px;
}
.section-title {
margin-bottom: 10px;
}
.title-text {
display: flex;
align-items: center;
gap: 8px; /* 调整文字和按钮之间的间距 */
font-weight: bold;
}
.title-text .el-button {
padding: 0;
height: auto;
font-size: 14px;
margin-left: 8px;
font-weight: normal;
color: #409eff;
}
.title-text .el-button:hover {
color: #66b1ff;
}
.title-text .el-button[disabled] {
color: #c0c4cc;
}
.section-title {
display: flex;
align-items: center;
justify-content: space-between;
margin-bottom: 10px;
}
.save-btn-container {
display: flex;
flex-direction: row;
align-items: center;
gap: 10px; /* 按钮之间的间距 */
}
.save-btn-container .el-button {
margin-left: 0; /* 重置按钮的左边距 */
}
/* 添加日期选择器容器样式 */
.date-picker-container {
padding: 10px 15px;
border-bottom: 1px solid #e6e6e6;
}
/* 修改日期选择器样式 */
:deep(.el-date-editor.el-input) {
width: 100%;
}
:deep(.el-date-editor .el-range-separator) {
padding: 0 5px;
}
:deep(.el-date-editor .el-range-input) {
width: 40%;
}
/* 添加加载状态样式 */
.loading-container {
padding: 20px;
}
:deep(.el-skeleton) {
width: 100%;
}
:deep(.el-skeleton__item) {
margin-bottom: 10px;
}
/* 添加禁用状态样式 */
:deep(.el-radio-group.is-disabled) {
opacity: 0.7;
}
:deep(.el-date-picker.is-disabled) {
opacity: 0.7;
}
:deep(.el-input.is-disabled) {
opacity: 0.7;
}
.reset-status-btn {
background-color: #ff7b7b;
color: white;
border: none;
padding: 5px 10px;
border-radius: 3px;
cursor: pointer;
transition: background-color 0.3s;
}
.reset-status-btn:hover {
background-color: #ff5b5b;
}
.patient-info {
width: 100%;
}
.info-row {
display: flex;
align-items: center;
justify-content: space-between;
flex-wrap: nowrap;
width: 100%;
}
.name {
font-weight: bold;
margin-right: 10px;
white-space: nowrap;
}
.medical-sn {
color: #909399;
font-size: 0.9em;
margin-right: 10px;
white-space: nowrap;
overflow: hidden;
text-overflow: ellipsis;
max-width: 100px;
}
.status-tag {
margin-right: 10px;
white-space: nowrap;
}
.reset-status-btn {
padding: 2px 8px;
height: 24px;
font-size: 12px;
white-space: nowrap;
}
</style>