Files
his/openhis-ui-vue3/src/views/inpatientDoctor/home/components/applicationShow/surgeryApplication.vue
关羽 256b986c0e Fix Bug #477: 住院医生工作站-住院检查申请详情弹窗中"发往科室"字段显示为短横线(-),未正常获取数据
根因:handleViewDetail 为同步方法,点击详情时 getLocationInfo 尚未返回,
orgOptions 为空导致 recursionFun 无法将 targetDepartment ID 解析为科室名称。

修复:
1. 前端(4个申请组件):handleViewDetail 改为 async,解析 descJson 前确保 orgOptions 已加载
2. 前端:watch encounterId 改为 Promise.all 并行加载数据和科室列表
3. 后端:新增 keyword 关键字筛选参数(申请单号/检查项目模糊匹配)

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
2026-05-11 14:03:49 +08:00

328 lines
8.9 KiB
Vue
Executable File

<!--
* @Author: sjjh
* @Date: 2025-09-05 21:16:06
* @Description: 手术申请详情
-->
<template>
<div class="report-container">
<div class="report-section">
<div class="report-title">
<span>手术申请</span>
<el-icon
class="report-refresh-icon"
:class="{ 'is-loading': loading }"
@click="handleRefresh"
>
<Refresh />
</el-icon>
</div>
<div class="report-table-wrapper">
<el-table
v-loading="loading"
:data="tableData"
border
size="small"
height="100%"
style="width: 100%"
>
<el-table-column type="index" label="序号" width="60" align="center" />
<el-table-column label="手术单号" width="160" align="center">
<template #default="scope">
<el-link type="primary" @click="handleViewDetail(scope.row)">
{{ scope.row.prescriptionNo || '-' }}
</el-link>
</template>
</el-table-column>
<el-table-column prop="patientName" label="患者姓名" width="120" />
<el-table-column prop="name" label="申请单名称" width="140" />
<el-table-column prop="createTime" label="创建时间" width="160" />
<el-table-column prop="requesterId_dictText" label="申请者" width="120" />
<el-table-column label="操作" align="center" fixed="right">
<template #default="scope">
<el-button link type="primary" icon="View" @click="handleViewDetail(scope.row)">详情</el-button>
</template>
</el-table-column>
</el-table>
</div>
</div>
<!-- 详情弹窗 -->
<el-dialog
v-model="detailDialogVisible"
title="手术申请详情"
width="800px"
destroy-on-close
top="5vh"
:close-on-click-modal="false"
>
<div v-if="currentDetail" class="applicationShow-container">
<div class="applicationShow-container-content">
<el-descriptions title="基本信息" :column="2">
<el-descriptions-item label="患者姓名">{{
currentDetail.patientName || '-'
}}</el-descriptions-item>
<el-descriptions-item label="申请单名称">{{
currentDetail.name || '-'
}}</el-descriptions-item>
<el-descriptions-item label="创建时间">{{
currentDetail.createTime || '-'
}}</el-descriptions-item>
<el-descriptions-item label="处方号">{{
currentDetail.prescriptionNo || '-'
}}</el-descriptions-item>
<el-descriptions-item label="申请者">{{
currentDetail.requesterId_dictText || '-'
}}</el-descriptions-item>
<el-descriptions-item label="就诊ID">{{
currentDetail.encounterId || '-'
}}</el-descriptions-item>
<el-descriptions-item label="申请单ID">{{
currentDetail.requestFormId || '-'
}}</el-descriptions-item>
</el-descriptions>
</div>
<div v-if="descJsonData && hasMatchedFields" class="applicationShow-container-content">
<el-descriptions title="申请单描述" :column="2">
<template v-for="(value, key) in descJsonData" :key="key">
<el-descriptions-item v-if="isFieldMatched(key)" :label="getFieldLabel(key)">
{{ value || '-' }}
</el-descriptions-item>
</template>
</el-descriptions>
</div>
<div
v-if="currentDetail.requestFormDetailList && currentDetail.requestFormDetailList.length"
class="applicationShow-container-table"
>
<el-table :data="currentDetail.requestFormDetailList" border>
<el-table-column type="index" label="序号" width="60" align="center" />
<el-table-column prop="adviceName" label="医嘱名称" />
<el-table-column prop="quantity" label="数量" width="80" align="center" />
<el-table-column prop="unitCode_dictText" label="单位" width="100" />
<el-table-column prop="totalPrice" label="总价" width="100" align="right" />
</el-table>
</div>
</div>
<template #footer>
<el-button icon="Close" @click="detailDialogVisible = false">关闭</el-button>
</template>
</el-dialog>
</div>
</template>
<script setup>
import {computed, getCurrentInstance, ref, watch} from 'vue';
import {Refresh} from '@element-plus/icons-vue';
import {patientInfo} from '../../store/patient.js';
import {getSurgery} from './api';
import {getOrgList} from '@/views/doctorstation/components/api.js';
const { proxy } = getCurrentInstance();
const tableData = ref([]);
const loading = ref(false);
const detailDialogVisible = ref(false);
const currentDetail = ref(null);
const descJsonData = ref(null);
const orgOptions = ref([]);
const fetchData = async () => {
if (!patientInfo.value?.encounterId) {
tableData.value = [];
loading.value = false;
return;
}
loading.value = true;
try {
const res = await getSurgery({ encounterId: patientInfo.value.encounterId });
if (res.code === 200 && res.data) {
const raw = res.data?.records || res.data;
const list = Array.isArray(raw) ? raw : [raw];
tableData.value = list.filter(Boolean);
} else {
tableData.value = [];
}
} catch (e) {
proxy.$modal?.msgError?.(e.message || '查询手术申请失败');
tableData.value = [];
} finally {
loading.value = false;
}
};
const handleRefresh = async () => {
if (loading.value || !patientInfo.value?.encounterId) return;
await fetchData();
};
const labelMap = {
categoryType: '项目类别',
targetDepartment: '发往科室',
symptom: '症状',
sign: '体征',
clinicalDiagnosis: '临床诊断',
otherDiagnosis: '其他诊断',
relatedResult: '相关结果',
attention: '注意事项',
};
const isFieldMatched = (key) => {
return key in labelMap;
};
const getFieldLabel = (key) => {
return labelMap[key] || key;
};
const hasMatchedFields = computed(() => {
if (!descJsonData.value) return false;
return Object.keys(descJsonData.value).some((key) => isFieldMatched(key));
});
/** 查询科室 */
const getLocationInfo = async () => {
const res = await getOrgList();
orgOptions.value = res.data.records;
};
const recursionFun = (targetDepartment) => {
let name = '';
for (let index = 0; index < orgOptions.value.length; index++) {
const obj = orgOptions.value[index];
if (obj.id == targetDepartment) {
name = obj.name;
}
const subObjArray = obj['children'];
for (let index = 0; index < subObjArray.length; index++) {
const item = subObjArray[index];
if (item.id == targetDepartment) {
name = item.name;
}
}
}
return name;
};
const handleViewDetail = async (row) => {
// 确保科室数据已加载,以便将 ID 解析为名称
if (!orgOptions.value || orgOptions.value.length === 0) {
await getLocationInfo();
}
currentDetail.value = row;
// 解析 descJson
if (row.descJson) {
try {
// descJsonData.value = JSON.parse(row.descJson);
const obj = JSON.parse(row.descJson);
obj.targetDepartment = recursionFun(obj.targetDepartment);
descJsonData.value = obj;
} catch (e) {
console.error('解析 descJson 失败:', e);
descJsonData.value = null;
}
} else {
descJsonData.value = null;
}
detailDialogVisible.value = true;
};
watch(
() => patientInfo.value?.encounterId,
async (val) => {
if (val) {
await Promise.all([fetchData(), getLocationInfo()]);
} else {
tableData.value = [];
}
},
{ immediate: true }
);
defineExpose({
refresh: fetchData,
});
</script>
<style scoped lang="scss">
.report-container {
display: flex;
flex-direction: column;
gap: 12px;
padding: 8px 0;
height: 100%;
}
.report-section {
background: #fff;
flex: 1;
min-height: 0;
display: flex;
flex-direction: column;
}
.report-title {
font-weight: 600;
margin-bottom: 8px;
display: flex;
align-items: center;
justify-content: space-between;
padding: 0 8px;
}
.report-table-wrapper {
flex: 1;
min-height: 0;
overflow: auto;
padding: 0 8px;
}
.report-refresh-icon {
cursor: pointer;
color: #909399;
transition: color 0.2s;
font-size: 18px;
}
.report-refresh-icon:hover {
color: #409eff;
}
.report-refresh-icon.is-loading {
animation: rotating 2s linear infinite;
}
@keyframes rotating {
0% {
transform: rotate(0deg);
}
100% {
transform: rotate(360deg);
}
}
:deep(.el-dialog__body) {
padding-top: 0 !important;
}
.applicationShow-container {
display: flex;
flex-direction: column;
max-height: 70vh;
width: 100%;
overflow-y: auto;
.applicationShow-container-content {
flex-shrink: 0;
margin-bottom: 0px;
}
.applicationShow-container-table {
flex-shrink: 0;
max-height: 300px;
overflow: auto;
}
}
</style>