Merge remote-tracking branch 'origin/develop' into develop
This commit is contained in:
File diff suppressed because it is too large
Load Diff
@@ -132,6 +132,13 @@
|
||||
prop="typeCode_dictText"
|
||||
:show-overflow-tooltip="true"
|
||||
/>
|
||||
<el-table-column
|
||||
label="报卡类型"
|
||||
align="center"
|
||||
key="reportTypeCode_dictText"
|
||||
prop="reportTypeCode_dictText"
|
||||
:show-overflow-tooltip="true"
|
||||
/>
|
||||
<el-table-column
|
||||
label="医保编码 "
|
||||
align="center"
|
||||
@@ -273,6 +280,20 @@
|
||||
</el-form-item>
|
||||
</el-col>
|
||||
</el-row>
|
||||
<el-row>
|
||||
<el-col :span="12">
|
||||
<el-form-item label="报卡类型" prop="reportTypeCode">
|
||||
<el-select v-model="form.reportTypeCode" placeholder="请选择" clearable>
|
||||
<el-option
|
||||
v-for="dict in card_name_code"
|
||||
:key="dict.value"
|
||||
:label="dict.label"
|
||||
:value="dict.value"
|
||||
></el-option>
|
||||
</el-select>
|
||||
</el-form-item>
|
||||
</el-col>
|
||||
</el-row>
|
||||
<el-row :gutter="24">
|
||||
<el-col :span="16">
|
||||
<el-form-item label="说明" prop="description">
|
||||
@@ -308,7 +329,7 @@ import {
|
||||
} from './components/disease';
|
||||
|
||||
const { proxy } = getCurrentInstance();
|
||||
const { condition_type_code } = proxy.useDict('condition_type_code');
|
||||
const { condition_type_code, card_name_code } = proxy.useDict('condition_type_code', 'card_name_code');
|
||||
|
||||
const diseaseList = ref([]);
|
||||
const open = ref(false);
|
||||
@@ -448,6 +469,7 @@ function reset() {
|
||||
statusEnum: undefined,
|
||||
sourceEnum: undefined,
|
||||
typeCode: undefined,
|
||||
reportTypeCode: undefined,
|
||||
description: undefined,
|
||||
ybFlag: undefined,
|
||||
ybNo: undefined,
|
||||
|
||||
@@ -948,6 +948,32 @@ export function deleteInspectionApplication(applyNo) {
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取检验类型列表(分类)
|
||||
*/
|
||||
export function getInspectionTypeList() {
|
||||
return request({
|
||||
url: '/system/inspection-type/list',
|
||||
method: 'get',
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取检验项目列表(从诊疗目录中筛选检验类项目)
|
||||
* @param {Object} queryParams - 查询参数
|
||||
* @param {string} queryParams.searchKey - 搜索关键词
|
||||
* @param {number} queryParams.pageNo - 页码
|
||||
* @param {number} queryParams.pageSize - 每页数量
|
||||
* @param {string} queryParams.categoryCode - 目录类别编码(检验)
|
||||
*/
|
||||
export function getInspectionItemList(queryParams) {
|
||||
return request({
|
||||
url: '/data-dictionary/diagnosis-treatment/information-page',
|
||||
method: 'get',
|
||||
params: queryParams,
|
||||
});
|
||||
}
|
||||
|
||||
// ========== 会诊相关接口 ==========
|
||||
/**
|
||||
* 获取会诊列表
|
||||
|
||||
@@ -0,0 +1,837 @@
|
||||
<template>
|
||||
<div class="exam-app-container">
|
||||
<!-- ====== 顶部卡片:申请单列表 ====== -->
|
||||
<div class="top-section">
|
||||
<div class="section-header">
|
||||
<span class="section-title">检查项目 ({{ applicationList.length }})</span>
|
||||
<div class="header-actions">
|
||||
<el-button type="primary" @click="handleAdd" icon="Plus">新增</el-button>
|
||||
<el-button type="success" @click="handleSave" icon="Finished">保存</el-button>
|
||||
</div>
|
||||
</div>
|
||||
<el-table
|
||||
v-loading="loading"
|
||||
:data="applicationList"
|
||||
:max-height="200"
|
||||
highlight-current-row
|
||||
@row-click="handleRowClick"
|
||||
border
|
||||
size="small"
|
||||
:header-cell-style="{ background: '#f5f5f5', color: '#303133', fontWeight: '600' }"
|
||||
>
|
||||
<el-table-column type="selection" width="40" align="center" />
|
||||
<el-table-column label="申请ID" prop="id" width="80" align="center" />
|
||||
<el-table-column label="申请单号" prop="applyNo" min-width="140" align="center" />
|
||||
<el-table-column label="申检部位" prop="inspectionArea" min-width="100" align="center" />
|
||||
<el-table-column label="申请医生" prop="applyDocCode" min-width="90" align="center" />
|
||||
<el-table-column label="急" prop="isUrgent" width="50" align="center">
|
||||
<template #default="{ row }">
|
||||
<el-checkbox v-model="row.isUrgent" :true-label="1" :false-label="0" disabled />
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column label="收费" prop="isCharged" width="50" align="center">
|
||||
<template #default="{ row }">
|
||||
<el-checkbox v-model="row.isCharged" :true-label="1" :false-label="0" disabled />
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column label="退费" prop="isRefunded" width="50" align="center">
|
||||
<template #default="{ row }">
|
||||
<el-checkbox v-model="row.isRefunded" :true-label="1" :false-label="0" disabled />
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column label="执行" prop="isExecuted" width="50" align="center">
|
||||
<template #default="{ row }">
|
||||
<el-checkbox v-model="row.isExecuted" :true-label="1" :false-label="0" disabled />
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column label="金额" prop="totalAmount" width="90" align="right">
|
||||
<template #default="{ row }">
|
||||
{{ (row.totalAmount || 0).toFixed(2) }}
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column label="操作" width="80" align="center" fixed="right">
|
||||
<template #default="{ row }">
|
||||
<el-button link @click.stop="handlePrint(row)" title="打印">
|
||||
<el-icon><Printer /></el-icon>
|
||||
</el-button>
|
||||
<el-button link type="danger" @click.stop="handleDelete(row)" title="删除">
|
||||
<el-icon><Delete /></el-icon>
|
||||
</el-button>
|
||||
</template>
|
||||
</el-table-column>
|
||||
</el-table>
|
||||
</div>
|
||||
|
||||
<!-- ====== 底部主区:左表单 + 右分类 ====== -->
|
||||
<div class="bottom-section">
|
||||
<!-- 左:表单区 -->
|
||||
<div class="form-panel">
|
||||
<el-tabs v-model="activeDetailTab" class="form-tabs">
|
||||
<!-- TAB1:检查申请单 -->
|
||||
<el-tab-pane label="检查申请单" name="applyForm">
|
||||
<el-form ref="formRef" :model="form" :rules="rules" size="small" class="apply-form">
|
||||
<el-row :gutter="12">
|
||||
<el-col :span="8">
|
||||
<el-form-item label="申请单号" prop="applyNo">
|
||||
<el-input v-model="form.applyNo" readonly />
|
||||
</el-form-item>
|
||||
</el-col>
|
||||
<el-col :span="8">
|
||||
<el-form-item label="姓名" prop="patientName">
|
||||
<el-input v-model="form.patientName" readonly />
|
||||
</el-form-item>
|
||||
</el-col>
|
||||
<el-col :span="8">
|
||||
<el-form-item label="就诊卡号" prop="medicalrecordNumber">
|
||||
<el-input v-model="form.medicalrecordNumber" readonly />
|
||||
</el-form-item>
|
||||
</el-col>
|
||||
</el-row>
|
||||
<el-row :gutter="12">
|
||||
<el-col :span="8">
|
||||
<el-form-item label="费用性质" prop="natureofCost">
|
||||
<el-select v-model="form.natureofCost" style="width:100%">
|
||||
<el-option label="自费医疗" value="自费医疗" />
|
||||
<el-option label="医保报销" value="医保报销" />
|
||||
</el-select>
|
||||
</el-form-item>
|
||||
</el-col>
|
||||
<el-col :span="8">
|
||||
<el-form-item label="申请日期" prop="applyTime">
|
||||
<el-date-picker v-model="form.applyTime" type="date" style="width:100%"
|
||||
format="YYYY-MM-DD" value-format="YYYY-MM-DD HH:mm:ss" />
|
||||
</el-form-item>
|
||||
</el-col>
|
||||
<el-col :span="8">
|
||||
<el-form-item label="申请科室" prop="applyDeptCode">
|
||||
<el-input v-model="form.applyDeptCode" />
|
||||
</el-form-item>
|
||||
</el-col>
|
||||
</el-row>
|
||||
<el-row :gutter="12">
|
||||
<el-col :span="8">
|
||||
<el-form-item label="申请医生" prop="applyDocCode">
|
||||
<el-input v-model="form.applyDocCode" />
|
||||
</el-form-item>
|
||||
</el-col>
|
||||
<el-col :span="8">
|
||||
<el-form-item label="执行科室" prop="performDeptCode">
|
||||
<el-input v-model="form.performDeptCode" />
|
||||
</el-form-item>
|
||||
</el-col>
|
||||
</el-row>
|
||||
<el-row :gutter="12">
|
||||
<el-col :span="24">
|
||||
<el-form-item label="诊断描述" prop="clinicDesc">
|
||||
<el-input v-model="form.clinicDesc" />
|
||||
</el-form-item>
|
||||
</el-col>
|
||||
</el-row>
|
||||
<el-row :gutter="12">
|
||||
<el-col :span="8">
|
||||
<el-form-item label="禁忌症" prop="contraindication">
|
||||
<el-input v-model="form.contraindication" />
|
||||
</el-form-item>
|
||||
</el-col>
|
||||
<el-col :span="8">
|
||||
<el-form-item label="临床诊断" prop="clinicalDiag">
|
||||
<el-input v-model="form.clinicalDiag" />
|
||||
</el-form-item>
|
||||
</el-col>
|
||||
<el-col :span="8">
|
||||
<el-form-item label="病史摘要" prop="medicalHistorySummary">
|
||||
<el-input v-model="form.medicalHistorySummary" />
|
||||
</el-form-item>
|
||||
</el-col>
|
||||
</el-row>
|
||||
<el-row :gutter="12">
|
||||
<el-col :span="24">
|
||||
<el-form-item label="检查目的" prop="purposeDesc">
|
||||
<el-input v-model="form.purposeDesc" />
|
||||
</el-form-item>
|
||||
</el-col>
|
||||
</el-row>
|
||||
<el-row :gutter="12">
|
||||
<el-col :span="8">
|
||||
<el-form-item label="体格检查">
|
||||
<el-input v-model="form.purposeofInspection" placeholder="T(摄氏度) P次/分 R次/分 BF" />
|
||||
</el-form-item>
|
||||
</el-col>
|
||||
<el-col :span="8">
|
||||
<el-form-item label="申检部位">
|
||||
<el-input v-model="form.inspectionArea" readonly />
|
||||
</el-form-item>
|
||||
</el-col>
|
||||
<el-col :span="8">
|
||||
<el-form-item label="检查方法">
|
||||
<el-input v-model="form.inspectionMethod" readonly />
|
||||
</el-form-item>
|
||||
</el-col>
|
||||
</el-row>
|
||||
<el-row :gutter="12">
|
||||
<el-col :span="8">
|
||||
<el-form-item label="备注" prop="applyRemark">
|
||||
<el-input v-model="form.applyRemark" />
|
||||
</el-form-item>
|
||||
</el-col>
|
||||
<el-col :span="16">
|
||||
<el-form-item label="状态">
|
||||
<el-checkbox v-model="form.isUrgent" :true-label="1" :false-label="0">急</el-checkbox>
|
||||
<el-checkbox v-model="form.isCharged" :true-label="1" :false-label="0" disabled>收费</el-checkbox>
|
||||
<el-checkbox v-model="form.isRefunded" :true-label="1" :false-label="0" disabled>退费</el-checkbox>
|
||||
<el-checkbox v-model="form.isExecuted" :true-label="1" :false-label="0" disabled>执行</el-checkbox>
|
||||
</el-form-item>
|
||||
</el-col>
|
||||
</el-row>
|
||||
</el-form>
|
||||
</el-tab-pane>
|
||||
|
||||
<!-- TAB2:检查明细 -->
|
||||
<el-tab-pane label="检查明细" name="applyDetail">
|
||||
<el-table
|
||||
ref="detailTableRef"
|
||||
:data="selectedItems"
|
||||
border
|
||||
size="small"
|
||||
style="width:100%"
|
||||
:max-height="350"
|
||||
:header-cell-style="{ background: '#f5f5f5', color: '#303133' }"
|
||||
>
|
||||
<el-table-column label="行" type="index" width="45" align="center" />
|
||||
<el-table-column label="检查项目" prop="name" min-width="120" />
|
||||
<el-table-column label="部位" prop="applyPart" min-width="90">
|
||||
<template #default="scope">
|
||||
<el-input v-model="scope.row.applyPart" size="small" />
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column label="单位" prop="unit" width="55" align="center" />
|
||||
<el-table-column label="总量" prop="quantity" width="70" align="center">
|
||||
<template #default="scope">
|
||||
<el-input-number v-model="scope.row.quantity" :min="1" size="small" :controls="false" style="width:100%" />
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column label="单价" prop="price" width="75" align="right" />
|
||||
<el-table-column label="金额" width="80" align="right">
|
||||
<template #default="scope">
|
||||
{{ ((scope.row.price || 0) * (scope.row.quantity || 1)).toFixed(2) }}
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column label="类型" prop="checkType" width="70" align="center" />
|
||||
<el-table-column label="国码" prop="nationalCode" width="70" align="center" />
|
||||
<el-table-column label="自费" width="50" align="center">
|
||||
<template #default>
|
||||
<el-checkbox disabled />
|
||||
</template>
|
||||
</el-table-column>
|
||||
</el-table>
|
||||
<div class="total-row">
|
||||
合计:<span class="total-amount">{{ totalAmountCalc }}</span>
|
||||
</div>
|
||||
</el-tab-pane>
|
||||
</el-tabs>
|
||||
</div>
|
||||
|
||||
<!-- 右:检查项目分类面板 -->
|
||||
<div class="category-panel">
|
||||
<div class="panel-top">
|
||||
<!-- 左侧:分类搜索 + 折叠树 -->
|
||||
<div class="category-left">
|
||||
<div class="panel-label">检查项目分类</div>
|
||||
<el-input
|
||||
v-model="dictSearchKey"
|
||||
placeholder="搜索检查项目(支持拼音首字母)"
|
||||
prefix-icon="Search"
|
||||
clearable
|
||||
size="small"
|
||||
class="search-input"
|
||||
/>
|
||||
<!-- 分类折叠列表 -->
|
||||
<div class="collapse-scroll" v-loading="dictLoading">
|
||||
<div v-if="filteredCategoryList.length === 0" class="empty-hint">
|
||||
{{ dictLoading ? '' : '暂无检查项目,请在"检查项目设置"中配置' }}
|
||||
</div>
|
||||
<el-collapse v-else v-model="activeNames">
|
||||
<el-collapse-item
|
||||
v-for="cat in filteredCategoryList"
|
||||
:key="cat.typeId"
|
||||
:name="cat.typeId"
|
||||
>
|
||||
<template #title>
|
||||
<span class="cat-title">{{ cat.categoryName }}</span>
|
||||
</template>
|
||||
<div
|
||||
v-for="item in cat.items"
|
||||
:key="item.id"
|
||||
class="item-row"
|
||||
>
|
||||
<el-checkbox
|
||||
v-model="item.checked"
|
||||
@change="(val) => handleItemSelect(val, item, cat)"
|
||||
class="item-checkbox"
|
||||
>
|
||||
{{ item.name }}
|
||||
</el-checkbox>
|
||||
<span class="item-price">¥{{ item.price }}</span>
|
||||
</div>
|
||||
</el-collapse-item>
|
||||
</el-collapse>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- 右侧:已选择 tags -->
|
||||
<div class="selected-panel">
|
||||
<div class="panel-label">已选择:</div>
|
||||
<div class="selected-tags">
|
||||
<div v-if="selectedItems.length === 0" class="empty-selected">–</div>
|
||||
<el-tag
|
||||
v-else
|
||||
v-for="(item, idx) in selectedItems"
|
||||
:key="idx"
|
||||
closable
|
||||
size="small"
|
||||
@close="handleRemoveItem(idx, item)"
|
||||
class="selected-tag"
|
||||
>
|
||||
{{ item.name }} ¥{{ item.price }}
|
||||
</el-tag>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script setup>
|
||||
import { ref, reactive, computed, watch, onMounted, nextTick } from 'vue';
|
||||
import { ElMessage, ElMessageBox } from 'element-plus';
|
||||
import { Printer, Delete } from '@element-plus/icons-vue';
|
||||
import useUserStore from '@/store/modules/user';
|
||||
import request from '@/utils/request';
|
||||
|
||||
const props = defineProps({
|
||||
patientInfo: { type: Object, default: () => ({}) },
|
||||
activeTab: { type: String, default: '' }
|
||||
});
|
||||
|
||||
// 保存成功后通知父组件刷新医嘱列表
|
||||
const emit = defineEmits(['saved']);
|
||||
|
||||
const userStore = useUserStore();
|
||||
const loading = ref(false);
|
||||
const dictLoading = ref(false);
|
||||
const activeDetailTab = ref('applyForm');
|
||||
const applicationList = ref([]);
|
||||
const selectedItems = ref([]);
|
||||
const detailTableRef = ref(null);
|
||||
const formRef = ref(null);
|
||||
|
||||
// ====== 表单数据 ======
|
||||
const form = reactive({
|
||||
applyNo: '',
|
||||
patientName: '',
|
||||
patientId: '',
|
||||
visitNo: '',
|
||||
applyDeptCode: '',
|
||||
performDeptCode: '',
|
||||
applyDocCode: '',
|
||||
applyTime: '',
|
||||
medicalrecordNumber: '',
|
||||
natureofCost: '自费医疗',
|
||||
clinicDesc: '',
|
||||
contraindication: '',
|
||||
medicalHistorySummary: '',
|
||||
purposeofInspection: '',
|
||||
inspectionArea: '',
|
||||
inspectionMethod: '',
|
||||
applyRemark: '',
|
||||
clinicalDiag: '',
|
||||
purposeDesc: '',
|
||||
isUrgent: 0,
|
||||
pregnancyState: 0,
|
||||
allergyDesc: '',
|
||||
applyStatus: 0,
|
||||
isCharged: 0,
|
||||
isRefunded: 0,
|
||||
isExecuted: 0,
|
||||
examTypeCode: '' // 检查类型编码,必填字段,保存时从已选项目自动推导
|
||||
});
|
||||
|
||||
const rules = {
|
||||
natureofCost: [{ required: true, message: '请选择费用性质', trigger: 'change' }],
|
||||
applyDeptCode: [{ required: true, message: '请输入申请科室', trigger: 'blur' }],
|
||||
applyDocCode: [{ required: true, message: '请输入申请医生', trigger: 'blur' }],
|
||||
performDeptCode: [{ required: true, message: '请输入执行科室', trigger: 'blur' }],
|
||||
clinicDesc: [{ required: true, message: '请输入诊断描述', trigger: 'blur' }],
|
||||
clinicalDiag: [{ required: true, message: '请输入临床诊断', trigger: 'blur' }],
|
||||
medicalHistorySummary: [{ required: true, message: '请输入病史摘要', trigger: 'blur' }],
|
||||
purposeDesc: [{ required: true, message: '请输入检查目的', trigger: 'blur' }]
|
||||
};
|
||||
|
||||
// ====== 检查项目分类 ======
|
||||
const categoryList = ref([]); // 原始分类+项目数据
|
||||
const dictSearchKey = ref('');
|
||||
const activeNames = ref([]); // 当前展开的折叠项
|
||||
|
||||
onMounted(async () => {
|
||||
await loadCategoryList();
|
||||
});
|
||||
|
||||
/**
|
||||
* 加载检查类型(分类)和检查项目(部位/项目),按类型分组展示
|
||||
*/
|
||||
async function loadCategoryList() {
|
||||
dictLoading.value = true;
|
||||
try {
|
||||
// 1. 加载检查类型(分类名称),只取父级
|
||||
const typeRes = await request({
|
||||
url: '/system/check-type/list',
|
||||
method: 'get',
|
||||
params: { pageNo: 1, pageSize: 500 } // 取全量分类数据
|
||||
});
|
||||
let types = [];
|
||||
if (typeRes.data?.records) types = typeRes.data.records;
|
||||
else if (Array.isArray(typeRes.data)) types = typeRes.data;
|
||||
else if (Array.isArray(typeRes.rows)) types = typeRes.rows;
|
||||
|
||||
// 2. 加载检查项目(检查部位项目)
|
||||
const partRes = await request({ url: '/check/part/list', method: 'get' });
|
||||
let parts = [];
|
||||
if (Array.isArray(partRes)) parts = partRes;
|
||||
else if (Array.isArray(partRes.data?.data)) parts = partRes.data.data; // 双层嵌套:{ data: { data: [...] } }
|
||||
else if (Array.isArray(partRes.data)) parts = partRes.data;
|
||||
else if (Array.isArray(partRes.rows)) parts = partRes.rows;
|
||||
else if (partRes.data?.records) parts = partRes.data.records;
|
||||
|
||||
// 3. 按 checkType 归类
|
||||
const dict = [];
|
||||
for (const t of types) {
|
||||
dict.push({
|
||||
typeId: t.id,
|
||||
typeCode: t.type,
|
||||
categoryName: t.name,
|
||||
items: []
|
||||
});
|
||||
}
|
||||
const unclassified = [];
|
||||
for (const p of parts) {
|
||||
const mapped = {
|
||||
id: p.id,
|
||||
name: p.name,
|
||||
price: p.price || 0,
|
||||
serviceFee: p.serviceFee || 0,
|
||||
unit: '次',
|
||||
checkType: p.checkType || '',
|
||||
nationalCode: p.nationalCode || '',
|
||||
checked: false
|
||||
};
|
||||
const target = dict.find(d => d.typeCode === p.checkType);
|
||||
if (target) target.items.push(mapped);
|
||||
else unclassified.push(mapped);
|
||||
}
|
||||
if (unclassified.length > 0) {
|
||||
dict.push({ typeId: 'uncls', typeCode: '', categoryName: '其他', items: unclassified });
|
||||
}
|
||||
categoryList.value = dict.filter(d => d.items.length > 0);
|
||||
|
||||
// 默认展开第一个
|
||||
if (categoryList.value.length > 0) {
|
||||
activeNames.value = [categoryList.value[0].typeId];
|
||||
}
|
||||
} catch (err) {
|
||||
console.error('加载检查项目分类失败', err);
|
||||
} finally {
|
||||
dictLoading.value = false;
|
||||
}
|
||||
}
|
||||
|
||||
/** 关键词过滤后的分类列表 */
|
||||
const filteredCategoryList = computed(() => {
|
||||
if (!dictSearchKey.value) return categoryList.value;
|
||||
const key = dictSearchKey.value.toLowerCase();
|
||||
return categoryList.value.map(cat => ({
|
||||
...cat,
|
||||
items: cat.items.filter(item => (item.name || '').toLowerCase().includes(key))
|
||||
})).filter(cat => cat.items.length > 0);
|
||||
});
|
||||
|
||||
// ====== 合计 ======
|
||||
const totalAmountCalc = computed(() => {
|
||||
const total = selectedItems.value.reduce((sum, item) => {
|
||||
return sum + (item.price * (item.quantity || 1));
|
||||
}, 0);
|
||||
return total.toFixed(2);
|
||||
});
|
||||
|
||||
// 监听已选项:自动更新申检部位
|
||||
watch(selectedItems, () => {
|
||||
form.inspectionArea = selectedItems.value.map(i => i.name).join('+');
|
||||
form.isCharged = selectedItems.value.length > 0 ? 1 : 0;
|
||||
}, { deep: true });
|
||||
|
||||
// 监听患者变化
|
||||
watch(() => props.patientInfo, (newVal) => {
|
||||
if (newVal?.encounterId) {
|
||||
initPatientForm(newVal);
|
||||
getList();
|
||||
}
|
||||
}, { immediate: true, deep: true });
|
||||
|
||||
watch(() => props.activeTab, (val) => {
|
||||
if (val === 'examination') getList();
|
||||
});
|
||||
|
||||
function initPatientForm(patient) {
|
||||
form.patientName = patient.patientName || '';
|
||||
form.medicalrecordNumber = patient.busNo || patient.visitNo || '';
|
||||
form.patientId = patient.patientId || '';
|
||||
form.visitNo = patient.visitNo || '';
|
||||
form.applyDeptCode = userStore.orgName || patient.organizationName || '';
|
||||
form.applyDocCode = userStore.nickName || '';
|
||||
}
|
||||
|
||||
// ====== 申请单 CRUD ======
|
||||
function getList() {
|
||||
loading.value = true;
|
||||
request({
|
||||
url: '/exam/apply/list',
|
||||
method: 'get',
|
||||
params: { visitNo: props.patientInfo?.visitNo || '' }
|
||||
}).then(res => {
|
||||
applicationList.value = res.rows || res.data || [];
|
||||
}).catch(err => console.error('获取申请单列表失败', err))
|
||||
.finally(() => { loading.value = false; });
|
||||
}
|
||||
|
||||
function handleAdd() {
|
||||
formRef.value?.resetFields();
|
||||
Object.assign(form, {
|
||||
applyNo: '', patientId: props.patientInfo?.patientId || '',
|
||||
visitNo: props.patientInfo?.visitNo || '',
|
||||
applyDeptCode: userStore.orgName || '',
|
||||
performDeptCode: '',
|
||||
applyDocCode: userStore.nickName || '',
|
||||
applyTime: new Date().toISOString().split('T')[0] + ' 12:00:00',
|
||||
medicalrecordNumber: props.patientInfo?.busNo || '',
|
||||
natureofCost: '自费医疗',
|
||||
clinicDesc: '', contraindication: '', medicalHistorySummary: '',
|
||||
purposeofInspection: '', inspectionArea: '', inspectionMethod: '',
|
||||
applyRemark: '', clinicalDiag: '', purposeDesc: '',
|
||||
isUrgent: 0, pregnancyState: 0, allergyDesc: '',
|
||||
applyStatus: 0, isCharged: 0, isRefunded: 0, isExecuted: 0
|
||||
});
|
||||
selectedItems.value = [];
|
||||
resetCategoryChecked();
|
||||
activeDetailTab.value = 'applyForm';
|
||||
}
|
||||
|
||||
function handleSave() {
|
||||
formRef.value.validate(valid => {
|
||||
if (!valid) return;
|
||||
if (selectedItems.value.length === 0) {
|
||||
ElMessage.warning('请至少选择一个检查明细项目');
|
||||
return;
|
||||
}
|
||||
// 从已选项目推导检查类型编码(取第一个项目的 checkType,如 CT / ECG / GI)
|
||||
const firstCheckType = selectedItems.value[0]?.checkType || 'unknown';
|
||||
if (!form.examTypeCode) form.examTypeCode = firstCheckType;
|
||||
|
||||
const payload = {
|
||||
...form,
|
||||
encounterId: props.patientInfo?.encounterId || null,
|
||||
patientIdNum: props.patientInfo?.patientId || null,
|
||||
items: selectedItems.value.map((item, index) => ({
|
||||
itemCode: String(item.id),
|
||||
itemName: item.name,
|
||||
bodyPartCode: item.checkType || 'unknown',
|
||||
itemFee: item.price,
|
||||
performDeptCode: form.performDeptCode || '',
|
||||
itemStatus: 0,
|
||||
itemSeq: index + 1
|
||||
}))
|
||||
};
|
||||
request({
|
||||
url: '/exam/apply',
|
||||
method: payload.applyNo ? 'put' : 'post',
|
||||
data: payload
|
||||
}).then(res => {
|
||||
ElMessage.success('保存成功');
|
||||
getList();
|
||||
if (res.data) form.applyNo = res.data;
|
||||
// 通知父组件刷新医嘱列表
|
||||
emit('saved');
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
function handleRowClick(row) {
|
||||
Object.assign(form, row);
|
||||
selectedItems.value = [];
|
||||
activeDetailTab.value = 'applyForm';
|
||||
request({ url: `/exam/apply/${row.applyNo}`, method: 'get' }).then(res => {
|
||||
const d = res.data || res;
|
||||
if (d.data) Object.assign(form, d.data);
|
||||
if (d.items && Array.isArray(d.items)) {
|
||||
selectedItems.value = d.items.map(m => ({
|
||||
id: m.itemCode, name: m.itemName,
|
||||
price: m.itemFee || 0, quantity: 1,
|
||||
serviceFee: 0, unit: '次',
|
||||
applyPart: m.itemName,
|
||||
checkType: m.bodyPartCode || '',
|
||||
nationalCode: '', checked: true
|
||||
}));
|
||||
syncCategoryChecked();
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
function handlePrint(row) { ElMessage.info('打印申请单:' + row.applyNo); }
|
||||
|
||||
function handleDelete(row) {
|
||||
ElMessageBox.confirm('确认删除该检查申请单吗?', '警告', { type: 'warning' }).then(() => {
|
||||
request({ url: `/exam/apply/${row.applyNo}`, method: 'delete' }).then(() => {
|
||||
ElMessage.success('删除成功');
|
||||
getList();
|
||||
if (form.applyNo === row.applyNo) handleAdd();
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
// ====== 勾选逻辑 ======
|
||||
function handleItemSelect(checked, item, cat) {
|
||||
if (checked) {
|
||||
selectedItems.value.push({
|
||||
id: item.id, name: item.name,
|
||||
price: item.price, quantity: 1,
|
||||
serviceFee: item.serviceFee || 0,
|
||||
unit: item.unit || '次',
|
||||
applyPart: item.name,
|
||||
checkType: cat.typeCode || '',
|
||||
nationalCode: item.nationalCode || '',
|
||||
checked: true
|
||||
});
|
||||
} else {
|
||||
const idx = selectedItems.value.findIndex(s => s.id === item.id);
|
||||
if (idx > -1) selectedItems.value.splice(idx, 1);
|
||||
}
|
||||
// 有选项时切换到明细tab
|
||||
if (selectedItems.value.length > 0) {
|
||||
activeDetailTab.value = 'applyDetail';
|
||||
nextTick(() => detailTableRef.value?.doLayout());
|
||||
}
|
||||
}
|
||||
|
||||
function handleRemoveItem(idx, item) {
|
||||
selectedItems.value.splice(idx, 1);
|
||||
// 取消对应 category 中的 checkbox
|
||||
for (const cat of categoryList.value) {
|
||||
const found = cat.items.find(x => x.id === item.id);
|
||||
if (found) { found.checked = false; break; }
|
||||
}
|
||||
}
|
||||
|
||||
function resetCategoryChecked() {
|
||||
for (const cat of categoryList.value)
|
||||
for (const item of cat.items) item.checked = false;
|
||||
}
|
||||
|
||||
function syncCategoryChecked() {
|
||||
resetCategoryChecked();
|
||||
const ids = new Set(selectedItems.value.map(s => s.id));
|
||||
for (const cat of categoryList.value)
|
||||
for (const item of cat.items)
|
||||
if (ids.has(item.id)) item.checked = true;
|
||||
}
|
||||
|
||||
defineExpose({ getList });
|
||||
</script>
|
||||
|
||||
<style scoped>
|
||||
.exam-app-container {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
gap: 10px;
|
||||
padding: 8px;
|
||||
height: 100%;
|
||||
background: #f0f2f5;
|
||||
}
|
||||
|
||||
/* 顶部申请单列表 */
|
||||
.top-section {
|
||||
background: #fff;
|
||||
border-radius: 4px;
|
||||
padding: 10px 12px;
|
||||
box-shadow: 0 1px 3px rgba(0,0,0,0.06);
|
||||
}
|
||||
.section-header {
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
align-items: center;
|
||||
margin-bottom: 10px;
|
||||
}
|
||||
.section-title {
|
||||
font-size: 14px;
|
||||
font-weight: 600;
|
||||
color: #303133;
|
||||
}
|
||||
.header-actions {
|
||||
display: flex;
|
||||
gap: 8px;
|
||||
}
|
||||
|
||||
/* 底部区域:左表单 + 右分类 */
|
||||
.bottom-section {
|
||||
display: flex;
|
||||
gap: 10px;
|
||||
flex: 1;
|
||||
min-height: 0;
|
||||
}
|
||||
|
||||
/* 左:表单面板 */
|
||||
.form-panel {
|
||||
flex: 1;
|
||||
background: #fff;
|
||||
border-radius: 4px;
|
||||
padding: 10px 12px;
|
||||
box-shadow: 0 1px 3px rgba(0,0,0,0.06);
|
||||
overflow-y: auto;
|
||||
min-width: 0;
|
||||
}
|
||||
.form-tabs :deep(.el-tabs__header) {
|
||||
margin-bottom: 10px;
|
||||
}
|
||||
.apply-form :deep(.el-form-item) {
|
||||
margin-bottom: 10px;
|
||||
}
|
||||
.apply-form :deep(.el-form-item__label) {
|
||||
font-size: 12px;
|
||||
}
|
||||
.total-row {
|
||||
margin-top: 8px;
|
||||
text-align: right;
|
||||
font-size: 13px;
|
||||
color: #606266;
|
||||
}
|
||||
.total-amount {
|
||||
font-size: 15px;
|
||||
font-weight: bold;
|
||||
color: #f56c6c;
|
||||
margin-left: 4px;
|
||||
}
|
||||
|
||||
/* 右:分类面板 */
|
||||
.category-panel {
|
||||
width: 380px;
|
||||
flex-shrink: 0;
|
||||
background: #fff;
|
||||
border-radius: 4px;
|
||||
box-shadow: 0 1px 3px rgba(0,0,0,0.06);
|
||||
padding: 10px 12px;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
overflow: hidden;
|
||||
}
|
||||
.panel-top {
|
||||
display: flex;
|
||||
gap: 12px;
|
||||
flex: 1;
|
||||
min-height: 0;
|
||||
}
|
||||
.category-left {
|
||||
flex: 1;
|
||||
min-width: 0;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
}
|
||||
.panel-label {
|
||||
font-size: 13px;
|
||||
font-weight: 600;
|
||||
color: #303133;
|
||||
margin-bottom: 6px;
|
||||
}
|
||||
.search-input {
|
||||
margin-bottom: 8px;
|
||||
}
|
||||
.collapse-scroll {
|
||||
flex: 1;
|
||||
overflow-y: auto;
|
||||
}
|
||||
.empty-hint {
|
||||
color: #909399;
|
||||
font-size: 12px;
|
||||
text-align: center;
|
||||
padding: 20px 0;
|
||||
}
|
||||
|
||||
/* 检查项目分类折叠 */
|
||||
.cat-title {
|
||||
font-size: 13px;
|
||||
font-weight: 500;
|
||||
color: #303133;
|
||||
}
|
||||
.item-row {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: space-between;
|
||||
padding: 3px 4px;
|
||||
}
|
||||
.item-row:hover {
|
||||
background: #f5f7fa;
|
||||
}
|
||||
.item-checkbox {
|
||||
flex: 1;
|
||||
overflow: hidden;
|
||||
}
|
||||
.item-checkbox :deep(.el-checkbox__label) {
|
||||
font-size: 12px;
|
||||
color: #303133;
|
||||
}
|
||||
.item-price {
|
||||
font-size: 12px;
|
||||
color: #1890FF;
|
||||
flex-shrink: 0;
|
||||
margin-left: 6px;
|
||||
}
|
||||
|
||||
/* 已选择 tags */
|
||||
.selected-panel {
|
||||
width: 120px;
|
||||
flex-shrink: 0;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
}
|
||||
.selected-tags {
|
||||
flex: 1;
|
||||
overflow-y: auto;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
gap: 4px;
|
||||
}
|
||||
.selected-tag {
|
||||
max-width: 100%;
|
||||
overflow: hidden;
|
||||
text-overflow: ellipsis;
|
||||
white-space: nowrap;
|
||||
}
|
||||
.empty-selected {
|
||||
color: #c0c4cc;
|
||||
font-size: 12px;
|
||||
}
|
||||
|
||||
/* 折叠组件细节 */
|
||||
:deep(.el-collapse) {
|
||||
border: none;
|
||||
}
|
||||
:deep(.el-collapse-item__header) {
|
||||
font-size: 13px;
|
||||
padding: 6px 0;
|
||||
height: auto;
|
||||
line-height: 1.5;
|
||||
}
|
||||
:deep(.el-collapse-item__content) {
|
||||
padding-bottom: 4px;
|
||||
}
|
||||
:deep(.el-collapse-item__wrap) {
|
||||
border: none;
|
||||
}
|
||||
</style>
|
||||
@@ -395,7 +395,7 @@
|
||||
<!-- 右侧:项目选择区(35%) -->
|
||||
<el-col :span="9" class="selection-area">
|
||||
<!-- 检验项目选择区(上部50%) -->
|
||||
<el-card class="inspection-selector">
|
||||
<el-card class="inspection-selector" v-loading="inspectionLoading" element-loading-text="正在加载检验项目...">
|
||||
<template #header>
|
||||
<span class="card-title">检验项目选择</span>
|
||||
</template>
|
||||
@@ -413,6 +413,9 @@
|
||||
|
||||
<!-- 分类树 -->
|
||||
<el-scrollbar class="category-tree" style="max-height: 280px">
|
||||
<!-- 无数据提示 -->
|
||||
<el-empty v-if="!inspectionLoading && inspectionCategories.length === 0" description="暂无检验项目数据" :image-size="80" />
|
||||
<!-- 数据列表 -->
|
||||
<div
|
||||
v-for="category in inspectionCategories"
|
||||
:key="category.key"
|
||||
@@ -487,22 +490,19 @@
|
||||
</template>
|
||||
|
||||
<script setup>
|
||||
import {onMounted, reactive, ref, watch} from 'vue'
|
||||
import {onMounted, reactive, ref, watch, nextTick} from 'vue'
|
||||
import {ElMessage, ElMessageBox} from 'element-plus'
|
||||
import { DocumentChecked, Plus, Document, Printer, Delete, Check } from '@element-plus/icons-vue'
|
||||
import {
|
||||
checkInspectionApplicationNo,
|
||||
deleteInspectionApplication, getApplyList,
|
||||
saveInspectionApplication
|
||||
saveInspectionApplication,
|
||||
getInspectionTypeList,
|
||||
getInspectionItemList
|
||||
} from '../api'
|
||||
import useUserStore from '@/store/modules/user.js'
|
||||
import {storeToRefs} from 'pinia'
|
||||
|
||||
// 在 onMounted 中调用初始化函数
|
||||
onMounted(() => {
|
||||
initData();
|
||||
})
|
||||
|
||||
// Props
|
||||
const props = defineProps({
|
||||
patientInfo: {
|
||||
@@ -529,9 +529,12 @@ const userStore = useUserStore()
|
||||
const { id: userId, name: userName, nickName: userNickName } = storeToRefs(userStore)
|
||||
|
||||
// 修改 initData 函数
|
||||
function initData() {
|
||||
// 然后执行原有的初始化逻辑
|
||||
if (props.patientInfo) {
|
||||
async function initData() {
|
||||
console.log('【检验】开始初始化数据,当前patientInfo:', props.patientInfo)
|
||||
|
||||
// 先初始化患者信息(如果有)
|
||||
if (props.patientInfo && props.patientInfo.encounterId) {
|
||||
console.log('【检验】初始化患者信息')
|
||||
queryParams.encounterId = props.patientInfo.encounterId
|
||||
formData.visitNo = props.patientInfo.busNo || ''
|
||||
formData.patientId = props.patientInfo.patientId || ''
|
||||
@@ -544,14 +547,21 @@ function initData() {
|
||||
formData.applyDeptCode = props.patientInfo.organizationName || ''
|
||||
formData.applyOrganizationId = props.patientInfo.orgId || ''
|
||||
formData.encounterId = props.patientInfo.encounterId
|
||||
|
||||
console.log('【检验】患者信息初始化完成,formData:', JSON.stringify({
|
||||
patientName: formData.patientName,
|
||||
medicalrecordNumber: formData.medicalrecordNumber,
|
||||
applyDepartment: formData.applyDepartment,
|
||||
applyDocName: formData.applyDocName
|
||||
}, null, 2))
|
||||
|
||||
// 生成申请单号
|
||||
generateApplicationNo().then((newApplyNo) => {
|
||||
formData.applyNo = newApplyNo;
|
||||
console.log('【检验】申请单号生成:', newApplyNo)
|
||||
});
|
||||
}
|
||||
|
||||
// 只有在存在 encounterId 时才调用接口
|
||||
if (queryParams.encounterId) {
|
||||
getInspectionList()
|
||||
} else {
|
||||
console.log('【检验】没有有效的patientInfo,跳过患者信息初始化')
|
||||
}
|
||||
}
|
||||
|
||||
@@ -567,10 +577,10 @@ const inspectionList = ref([])
|
||||
|
||||
// 表单数据
|
||||
const formData = reactive({
|
||||
applyOrganizationId: props.patientInfo.orgId,
|
||||
applyOrganizationId: '',
|
||||
applicationId: null,
|
||||
applyNo: '',
|
||||
patientId:'',
|
||||
patientId: '',
|
||||
patientName: '',
|
||||
medicalrecordNumber: '',
|
||||
natureofCost: 'self',
|
||||
@@ -596,10 +606,10 @@ const formData = reactive({
|
||||
auditDoctor: '',
|
||||
auditTime: null,
|
||||
visitNo: '',
|
||||
applyDocCode:'',
|
||||
applyDeptCode: props.patientInfo.organizationName,
|
||||
applyDocCode: '',
|
||||
applyDeptCode: '',
|
||||
specimenName: '血液',
|
||||
encounterId: props.patientInfo.encounterId
|
||||
encounterId: ''
|
||||
})
|
||||
|
||||
// 表单验证规则
|
||||
@@ -640,47 +650,173 @@ const selectedInspectionItems = ref([])
|
||||
const searchKeyword = ref('')
|
||||
|
||||
// 活动分类
|
||||
const activeCategory = ref('biochemical')
|
||||
const activeCategory = ref('')
|
||||
|
||||
// 检验项目分类(树形结构)
|
||||
let inspectionCategories = ref([
|
||||
{
|
||||
key: 'biochemical',
|
||||
label: '生化',
|
||||
expanded: true,
|
||||
items: [
|
||||
{ itemId: 1, itemName: '肝功能', itemPrice: 31, itemAmount: 31, sampleType: '血清', unit: 'U/L', itemQty: 1, serviceFee: 0, type: '生化', isSelfPay: false },
|
||||
{ itemId: 2, itemName: '肾功能', itemPrice: 28, itemAmount: 28, sampleType: '血清', unit: 'U/L', itemQty: 1, serviceFee: 0, type: '生化', isSelfPay: false },
|
||||
{ itemId: 3, itemName: '血糖', itemPrice: 15, itemAmount: 15, sampleType: '血清', unit: 'mmol/L', itemQty: 1, serviceFee: 0, type: '生化', isSelfPay: false }
|
||||
]
|
||||
},
|
||||
{
|
||||
key: 'blood',
|
||||
label: '临检',
|
||||
expanded: false,
|
||||
items: [
|
||||
{ itemId: 4, itemName: '血常规+crp', itemPrice: 50, itemAmount: 50, sampleType: '全血', unit: '×10^9/L', itemQty: 1, serviceFee: 0, type: '血液', isSelfPay: false },
|
||||
{ itemId: 5, itemName: '血常规(五分类)', itemPrice: 15, itemAmount: 15, sampleType: '全血', unit: '×10^9/L', itemQty: 1, serviceFee: 0, type: '血液', isSelfPay: false }
|
||||
]
|
||||
},
|
||||
{
|
||||
key: 'urine',
|
||||
label: '尿液',
|
||||
expanded: false,
|
||||
items: [
|
||||
{ itemId: 6, itemName: '尿常规', itemPrice: 20, itemAmount: 20, sampleType: '尿液', unit: '细胞/μl', itemQty: 1, serviceFee: 0, type: '尿液', isSelfPay: false }
|
||||
]
|
||||
},
|
||||
{
|
||||
key: 'immunity',
|
||||
label: '免疫',
|
||||
expanded: false,
|
||||
items: [
|
||||
{ itemId: 7, itemName: '总IgE测定', itemPrice: 30, itemAmount: 30, sampleType: '血清', unit: 'IU/ml', itemQty: 1, serviceFee: 0, type: '免疫', isSelfPay: false },
|
||||
{ itemId: 8, itemName: '风湿', itemPrice: 119, itemAmount: 119, sampleType: '血清', unit: 'U/ml', itemQty: 1, serviceFee: 0, type: '免疫', isSelfPay: false }
|
||||
]
|
||||
// 检验项目分类(动态从API获取)
|
||||
const inspectionCategories = ref([])
|
||||
|
||||
// 检验项目加载状态
|
||||
const inspectionLoading = ref(false)
|
||||
|
||||
// 加载检验项目分类和项目
|
||||
async function loadInspectionData() {
|
||||
// 如果已经加载过数据,直接返回(避免重复请求)
|
||||
if (inspectionCategories.value.length > 0) {
|
||||
console.log('【检验】数据已缓存,跳过重复加载')
|
||||
return
|
||||
}
|
||||
])
|
||||
|
||||
inspectionLoading.value = true
|
||||
const startTime = Date.now() // 性能监控开始时间
|
||||
|
||||
try {
|
||||
console.log('【检验】开始并行请求数据')
|
||||
|
||||
// 并行请求:同时获取检验类型列表和检验项目列表
|
||||
const [typeRes, itemRes] = await Promise.all([
|
||||
// 添加错误处理和重试机制
|
||||
getInspectionTypeList().catch(error => {
|
||||
console.error('【检验】获取检验类型失败:', error)
|
||||
return { data: [] } // 返回空数据作为降级方案
|
||||
}),
|
||||
getInspectionItemList({
|
||||
pageNo: 1,
|
||||
pageSize: 200, // 进一步优化:减少数据量,按需加载
|
||||
searchKey: '', // 添加搜索关键词参数
|
||||
categoryCode: 'inspection' // 明确指定检验类别
|
||||
}).catch(error => {
|
||||
console.error('【检验】获取检验项目失败:', error)
|
||||
return { data: { records: [] } } // 返回空数据作为降级方案
|
||||
})
|
||||
])
|
||||
|
||||
const endTime = Date.now()
|
||||
console.log(`【检验】API请求完成,耗时: ${endTime - startTime}ms`)
|
||||
|
||||
const typeList = typeRes.data || []
|
||||
console.log('【检验】获取到检验类型数量:', typeList.length)
|
||||
|
||||
// 解析检验项目数据
|
||||
let allItems = []
|
||||
if (itemRes.data && itemRes.data.records) {
|
||||
allItems = itemRes.data.records
|
||||
} else if (itemRes.data && Array.isArray(itemRes.data)) {
|
||||
allItems = itemRes.data
|
||||
} else if (Array.isArray(itemRes)) {
|
||||
allItems = itemRes
|
||||
}
|
||||
|
||||
console.log('【检验】获取到检验项目数量:', allItems.length)
|
||||
|
||||
// 按分类组织数据
|
||||
const categories = typeList
|
||||
.filter(type => type.validFlag === 1 || type.validFlag === undefined)
|
||||
.map((type, index) => {
|
||||
const categoryItems = allItems
|
||||
.filter(item => {
|
||||
const isInspection = item.categoryCode_dictText === '检验' ||
|
||||
item.categoryName === '检验' ||
|
||||
item.categoryCode === 'inspection'
|
||||
const matchType = item.typeName === type.name ||
|
||||
item.inspectionTypeName === type.name ||
|
||||
item.bigClassName === type.name ||
|
||||
item.typeCode === type.code
|
||||
return isInspection && (matchType || typeList.length === 1)
|
||||
})
|
||||
.map(item => ({
|
||||
itemId: item.id || item.activityId || Math.random().toString(36).substr(2, 9),
|
||||
itemName: item.name || item.itemName || '',
|
||||
itemPrice: item.retailPrice || item.price || 0,
|
||||
itemAmount: item.retailPrice || item.price || 0,
|
||||
sampleType: item.sampleType || '血液',
|
||||
unit: item.unit || '',
|
||||
itemQty: 1,
|
||||
serviceFee: 0,
|
||||
type: type.name,
|
||||
isSelfPay: false,
|
||||
activityId: item.activityId,
|
||||
code: item.code || item.activityCode
|
||||
}))
|
||||
|
||||
return {
|
||||
key: type.code || `type_${index}`,
|
||||
label: type.name || `分类${index + 1}`,
|
||||
expanded: index === 0,
|
||||
items: categoryItems
|
||||
}
|
||||
})
|
||||
|
||||
// 如果没有分类数据,但有项目数据,创建一个默认分类
|
||||
if (categories.length === 0 && allItems.length > 0) {
|
||||
const defaultItems = allItems
|
||||
.filter(item => item.categoryCode_dictText === '检验' ||
|
||||
item.categoryName === '检验' ||
|
||||
item.categoryCode === 'inspection' ||
|
||||
true)
|
||||
.slice(0, 50) // 优化:增加默认显示数量
|
||||
.map(item => ({
|
||||
itemId: item.id || item.activityId || Math.random().toString(36).substr(2, 9),
|
||||
itemName: item.name || item.itemName || '',
|
||||
itemPrice: item.retailPrice || item.price || 0,
|
||||
itemAmount: item.retailPrice || item.price || 0,
|
||||
sampleType: item.sampleType || '血液',
|
||||
unit: item.unit || '',
|
||||
itemQty: 1,
|
||||
serviceFee: 0,
|
||||
type: '检验',
|
||||
isSelfPay: false,
|
||||
activityId: item.activityId,
|
||||
code: item.code || item.activityCode
|
||||
}))
|
||||
|
||||
if (defaultItems.length > 0) {
|
||||
categories.push({
|
||||
key: 'default',
|
||||
label: '检验项目',
|
||||
expanded: true,
|
||||
items: defaultItems
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
// 过滤掉没有项目的分类
|
||||
const validCategories = categories.filter(cat => cat.items.length > 0)
|
||||
|
||||
if (validCategories.length > 0) {
|
||||
inspectionCategories.value = validCategories
|
||||
activeCategory.value = validCategories[0].key
|
||||
} else {
|
||||
throw new Error('未获取到有效的检验项目数据')
|
||||
}
|
||||
} catch (error) {
|
||||
console.error('加载检验项目数据失败:', error)
|
||||
// 加载失败时使用静态数据作为备用
|
||||
inspectionCategories.value = [
|
||||
{
|
||||
key: 'biochemical',
|
||||
label: '生化',
|
||||
expanded: true,
|
||||
items: [
|
||||
{ itemId: 1, itemName: '肝功能', itemPrice: 31, itemAmount: 31, sampleType: '血清', unit: 'U/L', itemQty: 1, serviceFee: 0, type: '生化', isSelfPay: false },
|
||||
{ itemId: 2, itemName: '肾功能', itemPrice: 28, itemAmount: 28, sampleType: '血清', unit: 'U/L', itemQty: 1, serviceFee: 0, type: '生化', isSelfPay: false },
|
||||
{ itemId: 3, itemName: '血糖', itemPrice: 15, itemAmount: 15, sampleType: '血清', unit: 'mmol/L', itemQty: 1, serviceFee: 0, type: '生化', isSelfPay: false }
|
||||
]
|
||||
},
|
||||
{
|
||||
key: 'blood',
|
||||
label: '临检',
|
||||
expanded: false,
|
||||
items: [
|
||||
{ itemId: 4, itemName: '血常规+crp', itemPrice: 50, itemAmount: 50, sampleType: '全血', unit: '×10^9/L', itemQty: 1, serviceFee: 0, type: '血液', isSelfPay: false },
|
||||
{ itemId: 5, itemName: '血常规(五分类)', itemPrice: 15, itemAmount: 15, sampleType: '全血', unit: '×10^9/L', itemQty: 1, serviceFee: 0, type: '血液', isSelfPay: false }
|
||||
]
|
||||
}
|
||||
]
|
||||
activeCategory.value = 'biochemical'
|
||||
} finally {
|
||||
inspectionLoading.value = false
|
||||
}
|
||||
}
|
||||
|
||||
// 获取过滤后的项目
|
||||
const getFilteredItems = (categoryKey) => {
|
||||
@@ -1374,23 +1510,30 @@ function handleCellClick(row, column) {
|
||||
watch(() => props.activeTab, async (newVal) => {
|
||||
if (newVal === 'inspection') {
|
||||
await initData()
|
||||
// 默认展开生化分类
|
||||
activeCategory.value = 'biochemical'
|
||||
inspectionCategories.value.forEach(cat => {
|
||||
cat.expanded = cat.key === 'biochemical'
|
||||
})
|
||||
// 根据动态加载的分类设置默认展开
|
||||
if (inspectionCategories.value.length > 0) {
|
||||
// 展开第一个分类
|
||||
activeCategory.value = inspectionCategories.value[0].key
|
||||
inspectionCategories.value.forEach((cat, index) => {
|
||||
cat.expanded = index === 0
|
||||
})
|
||||
}
|
||||
}
|
||||
})
|
||||
|
||||
// 监听patientInfo变化,确保encounterId及时更新并重新加载数据
|
||||
watch(() => props.patientInfo, async (newVal) => {
|
||||
// console.log('【检验】patientInfo变化:', newVal)
|
||||
console.log('【检验】patientInfo变化:', newVal)
|
||||
console.log('【检验】接收到的完整patientInfo:', JSON.stringify(newVal, null, 2))
|
||||
|
||||
if (newVal && newVal.encounterId) {
|
||||
const oldEncounterId = queryParams.encounterId
|
||||
queryParams.encounterId = newVal.encounterId
|
||||
// console.log('【检验】更新encounterId:', queryParams.encounterId)
|
||||
console.log('【检验】更新encounterId:', queryParams.encounterId)
|
||||
|
||||
// 初始化数据
|
||||
await initData();
|
||||
|
||||
// 如果encounterId发生变化,重新加载检验申请单列表
|
||||
if (oldEncounterId !== newVal.encounterId) {
|
||||
getInspectionList()
|
||||
@@ -1411,10 +1554,11 @@ watch(() => selectedInspectionItems.value, (newVal) => {
|
||||
}
|
||||
}, { deep: true })
|
||||
|
||||
// 初始化
|
||||
// 组件挂载时预加载检验项目数据(不依赖patientInfo)
|
||||
onMounted(async () => {
|
||||
await initData();
|
||||
getInspectionList();
|
||||
console.log('【检验】组件挂载,开始预加载检验项目数据')
|
||||
await loadInspectionData()
|
||||
console.log('【检验】检验项目数据预加载完成')
|
||||
})
|
||||
|
||||
// 暴露方法
|
||||
@@ -1523,6 +1667,7 @@ defineExpose({
|
||||
border-top: 1px solid var(--el-border-color-light);
|
||||
}
|
||||
|
||||
|
||||
:deep(.el-pagination) {
|
||||
.el-pager li {
|
||||
border-radius: 4px;
|
||||
|
||||
@@ -161,6 +161,10 @@
|
||||
<el-tab-pane label="检验" name="inspection">
|
||||
<inspectionApplication :patientInfo="patientInfo" :activeTab="activeTab" ref="inspectionRef" />
|
||||
</el-tab-pane>
|
||||
<el-tab-pane label="检查" name="examination">
|
||||
<examinationApplication :patientInfo="patientInfo" :activeTab="activeTab" ref="examinationRef"
|
||||
@saved="() => prescriptionRef?.getListInfo()" />
|
||||
</el-tab-pane>
|
||||
<el-tab-pane label="手术申请" name="surgery">
|
||||
<surgeryApplication :patientInfo="patientInfo" :activeTab="activeTab" ref="surgeryRef" />
|
||||
</el-tab-pane>
|
||||
@@ -215,6 +219,7 @@ import eprescriptionlist from './components/eprescriptionlist.vue';
|
||||
import HospitalizationDialog from './components/hospitalizationDialog.vue';
|
||||
import tcmAdvice from './components/tcm/tcmAdvice.vue';
|
||||
import inspectionApplication from './components/inspection/inspectionApplication.vue';
|
||||
import examinationApplication from './components/examination/examinationApplication.vue';
|
||||
import surgeryApplication from './components/surgery/surgeryApplication.vue';
|
||||
import DoctorCallDialog from './components/callQueue/DoctorCallDialog.vue';
|
||||
import { formatDate, formatDateStr } from '@/utils/index';
|
||||
@@ -306,6 +311,7 @@ const patientDrawerRef = ref();
|
||||
const prescriptionRef = ref();
|
||||
const tcmRef = ref();
|
||||
const inspectionRef = ref();
|
||||
const examinationRef = ref();
|
||||
const surgeryRef = ref();
|
||||
const emrRef = ref();
|
||||
const diagnosisRef = ref();
|
||||
@@ -496,6 +502,11 @@ function handleClick(tab) {
|
||||
inspectionRef.value.getList();
|
||||
}
|
||||
break;
|
||||
case 'examination':
|
||||
if (patientInfo.value && patientInfo.value.encounterId) {
|
||||
examinationRef.value.getList();
|
||||
}
|
||||
break;
|
||||
case 'surgery':
|
||||
surgeryRef.value.getList();
|
||||
break;
|
||||
@@ -607,6 +618,7 @@ function handleCardClick(item, index) {
|
||||
prescriptionRef.value.getListInfo();
|
||||
tcmRef.value.getListInfo();
|
||||
inspectionRef.value.getList();
|
||||
if(examinationRef.value) examinationRef.value.getList();
|
||||
surgeryRef.value.getList();
|
||||
diagnosisRef.value.getList();
|
||||
eprescriptionRef.value.getList();
|
||||
|
||||
Reference in New Issue
Block a user