Files
his/openhis-ui-vue3/src/views/inpatientDoctor/home/components/diagnosis/diagnosis.vue
zhangfei 9c3e603b94 Fix Bug #443: 手术计费:点击签发耗材时异常报错
当手术计费弹窗中点击"签发"耗材时,因耗材的locationId(发放库房)为空导致后端异常。
在DoctorStationAdviceAppServiceImpl.handDevice方法中,当locationId为null时,使用登录用户的科室ID作为默认值,
与NurseBillingAppService中的处理方式保持一致。
2026-05-08 09:14:18 +08:00

727 lines
22 KiB
Vue
Executable File
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>
<el-row :gutter="24">
<el-col :span="4" :xs="24">
<el-input
v-model="diagnosis"
placeholder="诊断名称"
clearable
style="width: 100%; margin-bottom: 10px"
@keyup.enter="queryDiagnosisUse"
>
<template #append>
<el-button icon="Search" @click="queryDiagnosisUse" />
</template>
</el-input>
<el-tree
ref="treeRef"
:data="tree"
node-key="id"
:props="{ label: 'name', children: 'children' }"
highlight-current
default-expand-all
:filter-node-method="filterNode"
@node-click="handleNodeClick"
>
<template #default="{ node, data }">
<div class="custom-tree-node">
<span>{{ node.label }}</span>
<span class="tree-node-actions">
<template v-if="node.level === 1 && data.name != '常用' && data.name != '历史'">
<el-button
style="color: #000000"
type="text"
size="small"
@click.stop="addChild(data)"
>
<el-icon>
<Plus />
</el-icon>
</el-button>
</template>
<el-popconfirm width="200" :hide-after="10" title="确认删除此常用诊断吗" placement="top-start"
@confirm="deleteChild(data)">
<template #reference>
<el-button
style="color: #000000"
v-if="
node.level === 2 &&
node.parent.data.name != '常用' &&
node.parent.data.name != '历史'
"
type="text"
size="small"
@click.stop=""
>
<el-icon>
<Minus />
</el-icon>
</el-button>
</template>
</el-popconfirm>
</span>
</div>
</template>
</el-tree>
</el-col>
<el-col :span="20" :xs="24">
<div style="margin-bottom: 10px">
<el-button type="primary" plain @click="handleAddDiagnosis()"> 新增诊断 </el-button>
<el-button type="primary" plain @click="handleSaveDiagnosis()"> 保存诊断 </el-button>
<!-- <el-button type="primary" plain @click="handleAddTcmDiagonsis()"> 中医诊断 </el-button> -->
<el-button type="primary" plain @click="handleImport()"> 导入慢性病诊断 </el-button>
</div>
<el-form :model="form" :rules="rules" ref="formRef">
<el-table ref="diagnosisTableRef" :data="form.diagnosisList" height="650">
<el-table-column label="序号" width="50" >
<template #default="scope">
{{ scope.$index + 1 }}
</template>
</el-table-column>
<el-table-column label="诊断排序" align="center" prop="diagSrtNo" width="120">
<template #default="scope">
<el-form-item :prop="`diagnosisList.${scope.$index}.diagSrtNo`" :rules="rules.diagSrtNo">
<el-input-number v-model="scope.row.diagSrtNo" controls-position="right" :controls="false"
style="width: 80px" />
</el-form-item>
</template>
</el-table-column>
<el-table-column label="诊断类别" align="center" prop="diagSrtNo" width="180">
<template #default="scope">
<el-form-item :prop="`diagnosisList.${scope.$index}.medTypeCode`" :rules="rules.medTypeCode">
<el-select v-model="scope.row.medTypeCode" placeholder=" " style="width: 150px">
<el-option v-for="item in med_type" :key="item.value" :label="item.label" :value="item.value" />
</el-select>
</el-form-item>
</template>
</el-table-column>
<el-table-column label="诊断名称" align="center" prop="name">
<template #default="scope">
<el-form-item :prop="`diagnosisList.${scope.$index}.name`" :rules="rules.name">
<el-popover :popper-style="{ padding: '0' }" placement="bottom-start" :visible="scope.row.showPopover"
trigger="manual" :width="800">
<diagnosislist :diagnosisSearchkey="diagnosisSearchkey" @selectDiagnosis="handleSelsectDiagnosis" />
<template #reference>
<el-input v-model="scope.row.name" placeholder="请选择诊断" @input="handleChange"
@focus="handleFocus(scope.row, scope.$index)" @blur="handleBlur(scope.row)" />
</template>
</el-popover>
</el-form-item>
</template>
</el-table-column>
<el-table-column label="诊断医生" align="center" prop="diagnosisDoctor" width="120" />
<el-table-column label="诊断时间" align="center" prop="diagnosisTime" width="150" />
<el-table-column label="诊断代码" align="center" prop="ybNo" width="180" />
<el-table-column label="诊断类型" align="center" prop="maindiseFlag" width="120">
<template #default="scope">
<div style="display:flex;flex-direction:column;align-items:center;gap:5px;">
<el-checkbox
label="主诊断"
:trueLabel="1"
:falseLabel="0"
v-model="scope.row.maindiseFlag"
border
size="small"
@change="(value) => handleMaindise(value, scope.$index)"
/>
<el-select
v-model="scope.row.verificationStatusEnum"
placeholder=" "
style="width: 100%; padding-bottom: 5px; padding-left: 10px"
size="small"
>
<el-option
v-for="item in diagnosisOptions"
:key="item.value"
:label="item.label"
:value="item.value"
/>
</el-select>
</div>
</template>
</el-table-column>
<el-table-column label="操作" align="center" width="130">
<template #default="scope">
<el-button link type="primary" @click="handleDeleteDiagnosis(scope.row, scope.$index)">
删除
</el-button>
</template>
</el-table-column>
</el-table>
</el-form>
</el-col>
</el-row>
<diagnosisdialog
:openDiagnosis="openDiagnosis"
@close="closeDiagnosisDialog"
:radio="orgOrUser"
/>
<AddDiagnosisDialog
:openAddDiagnosisDialog="openAddDiagnosisDialog"
:patientInfo="props.patientInfo"
@close="closeDiagnosisDialog"
/>
</div>
</template>
<script setup>
import {getCurrentInstance} from 'vue'; // 添加 nextTick 导入
import useUserStore from '@/store/modules/user';
import {
delEncounterDiagnosis,
deleteDiagnosisBind,
diagnosisInit,
getChronicDisease,
getConditionDefinitionInfo,
getEmrDetail,
getEncounterDiagnosis,
getTcmDiagnosis,
isFoodDiseasesNew,
saveDiagnosis,
} from '../api';
import {deleteTcmDiagnosis} from '@/views/doctorstation/components/api.js';
import diagnosisdialog from '../diagnosis/diagnosisdialog.vue';
import AddDiagnosisDialog from './addDiagnosisDialog.vue';
import diagnosislist from '../diagnosis/diagnosislist.vue';
import {patientInfo} from '../../store/patient.js';
import {ElMessage} from 'element-plus';
// const diagnosisList = ref([]);
const allowAdd = ref(false);
const isSaving = ref(false);
const tree = ref([]);
const openDiagnosis = ref(false);
const openAddDiagnosisDialog = ref(false);
const diagnosisSearchkey = ref('');
const diagnosisOptions = ref([]);
const rowIndex = ref();
const diagnosis = ref();
const orgOrUser = ref();
const form = ref({
diagnosisList: [],
});
const props = defineProps({
patientInfo: {
type: Object,
required: false,
default: () => ({}),
},
});
const emits = defineEmits(['diagnosisSave']);
const { proxy } = getCurrentInstance();
const userStore = useUserStore();
const { med_type } = proxy.useDict('med_type');
const rules = ref({
name: [{ required: true, message: '请选择诊断', trigger: 'change' }],
medTypeCode: [{ required: true, message: '请选择诊断类型', trigger: 'change' }],
diagSrtNo: [{ required: true, message: '请输入诊断序号', trigger: 'change' }],
});
const diagnosisNetDatas = ref([]);
watch(
() => form.value.diagnosisList,
() => {
// 如果正在保存,则不触发更新事件
if (!isSaving.value) {
emits('diagnosisSave', false);
}
},
{ deep: true }
);
// 监听患者信息变化,自动获取病历详情和诊断列表
watch(
() => props.patientInfo,
(newVal) => {
if (newVal?.encounterId) {
getDetail(newVal.encounterId);
getList();
}
},
{ immediate: true, deep: true }
);
function getDetail(encounterId) {
if (!encounterId) {
console.warn('未提供有效的就诊ID无法获取病历详情');
allowAdd.value = false;
return;
}
console.log('正在获取病历详情encounterId:', encounterId);
getEmrDetail(encounterId)
.then((res) => {
console.log('病历详情API返回:', res);
if (res.code === 200) {
allowAdd.value = res.data ? true : false;
console.log('设置 allowAdd =', allowAdd.value, ', 病历数据:', res.data);
} else {
allowAdd.value = false;
console.warn('获取病历详情失败:', res.msg);
}
})
.catch((error) => {
console.error('获取病历详情异常:', error);
allowAdd.value = false;
});
}
function getList() {
if (!props.patientInfo || !props.patientInfo.encounterId) {
console.warn('患者就诊信息不完整,无法获取诊断数据');
return;
}
// 初始化中医诊断列表
const newList = [];
getEncounterDiagnosis(props.patientInfo.encounterId).then((res) => {
if (res.code == 200) {
const datas = (res.data || []).map((item) => {
let obj = {
...item,
};
if (obj.diagSrtNo == null) {
obj.diagSrtNo = '1';
}
return obj;
});
form.value.diagnosisList = datas;
// form.value.diagnosisList = res.data;
emits('diagnosisSave', false);
}
});
getTcmDiagnosis({ encounterId: props.patientInfo.encounterId }).then((res) => {
console.log('getTcmDiagnosis=======>', JSON.stringify(res.data.illness));
if (res.code == 200) {
if (res.data.illness.length > 0) {
diagnosisNetDatas.value = res.data.illness;
res.data.illness.forEach((item, index) => {
newList.push({
name: item.name + '-' + (res.data.symptom[index]?.name || ''),
ybNo: item.ybNo,
medTypeCode: item.medTypeCode,
diagnosisDoctor: props.patientInfo.practitionerName || props.patientInfo.doctorName || props.patientInfo.physicianName || userStore.name,
diagnosisTime: new Date().toLocaleString('zh-CN')
});
});
// 将新数据添加到现有列表中
form.value.diagnosisList.push(...newList);
// 重新排序整个列表
form.value.diagnosisList.sort((a, b) => {
const aNo = typeof a.diagSrtNo === 'number' ? a.diagSrtNo : 9999;
const bNo = typeof b.diagSrtNo === 'number' ? b.diagSrtNo : 9999;
return aNo - bNo;
});
}
emits('diagnosisSave', false);
}
});
getTree();
}
init();
function init() {
diagnosisInit().then((res) => {
if (res.code == 200) {
diagnosisOptions.value = res.data.verificationStatusOptions;
}
});
}
function handleImport() {
if (!props.patientInfo || !props.patientInfo.encounterId) {
return;
}
if (props.patientInfo.contractName != '自费') {
// 获取患者慢性病信息
getChronicDisease({ encounterId: props.patientInfo.encounterId }).then((res) => {
if (res.data && res.data.length > 0) {
res.data.forEach((item, index) => {
form.value.diagnosisList.push({
...item,
...{
medTypeCode: '140104',
verificationStatusEnum: 4,
definitionId: item.id,
diagSrtNo: form.value.diagnosisList.length + 1,
iptDiseTypeCode: 2,
diagnosisDesc: '',
diagnosisDoctor: props.patientInfo.practitionerName || props.patientInfo.doctorName || props.patientInfo.physicianName || userStore.name,
diagnosisTime: new Date().toLocaleString('zh-CN'),
//添加 patientId
patientId: props.patientInfo.patientId
},
});
});
}
});
}
}
/**
* 添加子节点
*/
function addChild(data) {
orgOrUser.value = data.name;
openDiagnosis.value = true;
}
/**
* 删除子节点
*/
function deleteChild(data) {
deleteDiagnosisBind(data.id).then((res) => {
if (res.code == 200) {
proxy.$modal.msgSuccess('删除成功');
getTree();
}
});
}
watch(diagnosis, (val) => {
proxy.$refs['treeRef'].filter(val);
});
/** 通过条件过滤节点 */
const filterNode = (value, data) => {
console.log('filterNode', value, data);
if (!value) return true;
return data.name.indexOf(value) !== -1;
};
/**
* 获取诊断树列表
*/
function getTree() {
const patientId = props.patientInfo?.patientId || '';
getConditionDefinitionInfo(patientId).then((res) => {
if (res.code == 200) {
let list = [];
list = res.data.patientHistoryList;
list.children = [];
// 手动构造树列表;
tree.value[0] = {
id: '1',
name: '历史',
children: list,
};
tree.value[1] = {
id: '2',
name: '常用',
children: res.data.doctorCommonUseList,
};
tree.value[2] = {
id: '3',
name: '个人',
children: res.data.userPersonalList,
};
tree.value[3] = {
id: '4',
name: '科室',
children: res.data.organizationList,
};
console.log(tree.value);
}
});
}
/**
* 添加西医诊断
*/
function handleAddDiagnosis() {
console.log('点击新增诊断按钮allowAdd:', allowAdd.value);
// 检查表单ref是否存在
if (!proxy.$refs.formRef) {
console.error('表单ref不存在');
// 直接添加诊断,不经过表单验证
addDiagnosisItem();
return;
}
proxy.$refs.formRef.validate((valid, fields) => {
console.log('表单验证结果:', valid, '错误字段:', fields);
if (valid) {
if (!allowAdd.value) {
proxy.$modal.msgWarning('请先填写病历');
return;
}
addDiagnosisItem();
} else {
console.warn('表单验证失败:', fields);
// 验证失败时也允许添加(因为是新增空行)
if (allowAdd.value) {
console.log('验证失败但允许添加,强制添加诊断');
addDiagnosisItem();
}
}
});
}
/**
* 添加诊断项
*/
function addDiagnosisItem() {
form.value.diagnosisList.push({
showPopover: false,
name: undefined,
verificationStatusEnum: 4,
medTypeCode: undefined,
diagSrtNo: form.value.diagnosisList.length + 1,
iptDiseTypeCode: 2,
diagnosisDesc: '',
diagnosisDoctor: props.patientInfo.practitionerName || props.patientInfo.doctorName || props.patientInfo.physicianName || userStore.name,
diagnosisTime: new Date().toLocaleString('zh-CN'),
// 新增这一行:为每个诊断项添加 patientId
patientId: props.patientInfo.patientId
});
if (form.value.diagnosisList.length == 1) {
form.value.diagnosisList[0].maindiseFlag = 1;
}
}
// 添加中医诊断
function handleAddTcmDiagonsis() {
openAddDiagnosisDialog.value = true;
}
/**
* 删除诊断
*/
/**
* 删除诊断
*/
function handleDeleteDiagnosis(row, index) {
//中医诊断用-拼接 例如:疳气-表里俱实证
const nameArr = row.name?.split('-') || [];
if (row.conditionId) {
if (nameArr.length > 1) {
deleteTcmDiagnosis(row.syndromeGroupNo).then(() => {
getList();
getTree();
});
} else {
delEncounterDiagnosis(row.conditionId).then(() => {
getList();
getTree();
});
}
} else {
console.log('row============>', JSON.stringify(row));
console.log('item============>', index);
if (nameArr.length > 1) {
let obj = null;
for (let index = 0; index < diagnosisNetDatas.value.length; index++) {
const item = diagnosisNetDatas.value[index];
console.log('item.name============>', item.name);
console.log('row.name============>', row.name);
if (item.ybNo == row.ybNo) {
obj = item;
}
}
deleteTcmDiagnosis(obj.syndromeGroupNo).then(() => {
getList();
getTree();
});
} else {
form.value.diagnosisList.splice(index, 1);
}
}
}
function handleMaindise(value, index) {
if (value == 1) {
let flag = 0;
form.value.diagnosisList.forEach((item) => {
console.log(item);
if (item.maindiseFlag == 1) {
flag++;
}
});
if (flag > 1) {
form.value.diagnosisList[index].maindiseFlag = 0;
proxy.$modal.msgWarning('只能有一条主诊断');
}
}
}
/**
* 保存诊断
*/
/**
* 保存诊断
*/
/**
* 保存诊断
*/
/**
* 保存诊断
*/
function handleSaveDiagnosis() {
for (let index = 0; index < (form.value.diagnosisList || []).length; index++) {
const item = form.value.diagnosisList[index];
if (!item.diagSrtNo) {
ElMessage({
type: 'error',
message: '请录入诊断序号',
});
break;
}
}
proxy.$refs.formRef.validate((valid) => {
if (valid) {
if (form.value.diagnosisList.length === 0) {
proxy.$modal.msgWarning('诊断不能为空');
return;
} else if (!form.value.diagnosisList.some((diagnosis) => diagnosis.maindiseFlag === 1)) {
proxy.$modal.msgWarning('至少添加一条主诊断');
return;
}
// 设置保存标志避免触发watch监听器
isSaving.value = true;
// 步骤1深拷贝并按 diagSrtNo 排序
const sortedList = [...form.value.diagnosisList].sort((a, b) => {
const aNo = typeof a.diagSrtNo === 'number' ? a.diagSrtNo : 9999;
const bNo = typeof b.diagSrtNo === 'number' ? b.diagSrtNo : 9999;
return aNo - bNo;
});
// 步骤2重新分配连续的序号从1开始
sortedList.forEach((item, index) => {
item.diagSrtNo = index + 1; // 这里是关键!把“诊断排序”改成新顺序
});
// 步骤3提交排序后的数据
saveDiagnosis({
patientId: props.patientInfo.patientId,
encounterId: props.patientInfo.encounterId,
diagnosisChildList: sortedList,
}).then((res) => {
if (res.code === 200) {
// 步骤4更新本地数据使用全新对象防止响应式问题
form.value.diagnosisList = sortedList.map(item => ({ ...item }));
emits('diagnosisSave', false);
proxy.$modal.msgSuccess('诊断已保存');
// 食源性疾病逻辑
isFoodDiseasesNew({ encounterId: props.patientInfo.encounterId }).then((res2) => {
if (res2.code === 20 && res2.data) {
window.open(res2.data, '_blank');
}
});
}
}).finally(() => {
setTimeout(() => {
isSaving.value = false;
}, 100);
});
}
});
}
/**
* 关闭诊断弹窗
*/
function closeDiagnosisDialog(str) {
if (str === 'success') {
proxy.$modal.msgSuccess('操作成功');
}
openAddDiagnosisDialog.value = false;
openDiagnosis.value = false;
getTree();
getList();
}
function queryDiagnosisUse(value) { }
function handleChange(value) {
diagnosisSearchkey.value = value;
}
/**
* 选择诊断并赋值到列表
*/
function handleSelsectDiagnosis(row) {
console.log(row);
form.value.diagnosisList[rowIndex.value].ybNo = row.ybNo;
form.value.diagnosisList[rowIndex.value].name = row.name;
form.value.diagnosisList[rowIndex.value].definitionId = row.id;
}
/**获取焦点时 打开列表 */
function handleFocus(row, index) {
rowIndex.value = index;
row.showPopover = true;
}
/**失去焦点时 关闭列表 */
function handleBlur(row) {
row.showPopover = false;
}
function handleNodeClick(data) {
console.log(data.children);
// 检查节点是否为根节点
if (data.children != undefined) {
// 如果是根节点,不执行任何操作
return;
}
// if (!allowAdd.value) {
// proxy.$modal.msgWarning('请先填写病历');
// return;
// }
const isDuplicate = form.value.diagnosisList.some(
(diagnosis) => diagnosis.ybNo === data.ybNo || diagnosis.name === data.name
);
if (isDuplicate) {
proxy.$modal.msgWarning('该诊断项已存在');
return;
}
form.value.diagnosisList.push({
ybNo: data.ybNo,
name: data.name,
verificationStatusEnum: 4,
medTypeCode: undefined,
diagSrtNo: form.value.diagnosisList.length + 1,
definitionId: data.definitionId,
diagnosisDoctor: props.patientInfo.practitionerName || props.patientInfo.doctorName || props.patientInfo.physicianName || userStore.name,
diagnosisTime: new Date().toLocaleString('zh-CN'),
// 添加 patientId
patientId: props.patientInfo.patientId
});
if (form.value.diagnosisList.length == 1) {
form.value.diagnosisList[0].maindiseFlag = 1;
}
}
defineExpose({ getList, getDetail, handleSaveDiagnosis });
</script>
<style lang="scss" scoped>
.el-checkbox.is-bordered.el-checkbox--small {
background-color: #ffffff;
}
.custom-tree-node {
display: flex;
align-items: center;
justify-content: space-between;
width: 100%;
}
.tree-node-actions {
display: flex;
align-items: center;
}
</style>