Files
his/openhis-ui-vue3/src/views/inpatientDoctor/home/components/diagnosis/diagnosis.vue

674 lines
21 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>
<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, nextTick } from 'vue'; // 添加 nextTick 导入
import useUserStore from '@/store/modules/user';
import {
getConditionDefinitionInfo,
saveDiagnosis,
diagnosisInit,
deleteDiagnosisBind,
getEncounterDiagnosis,
getEmrDetail,
getChronicDisease,
getTcmDiagnosis,
delEncounterDiagnosis,
isFoodDiseasesNew,
} from '../api';
import diagnosisdialog from '../diagnosis/diagnosisdialog.vue';
import AddDiagnosisDialog from './addDiagnosisDialog.vue';
import diagnosislist from '../diagnosis/diagnosislist.vue';
// const diagnosisList = ref([]);
const allowAdd = 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: true,
},
});
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 isSaving = ref(false);
watch(
() => form.value.diagnosisList,
() => {
// 如果正在保存,则不触发更新事件
if (!isSaving.value) {
emits('diagnosisSave', false);
}
},
{ deep: true }
);
function getDetail(encounterId) {
if (!encounterId) {
console.warn('未提供有效的就诊ID无法获取病历详情');
return;
}
getEmrDetail(encounterId).then((res) => {
allowAdd.value = res.data ? true : false;
});
}
function getList() {
if (!props.patientInfo || !props.patientInfo.encounterId) {
console.warn('患者就诊信息不完整,无法获取诊断数据');
return;
}
getEncounterDiagnosis(props.patientInfo.encounterId).then((res) => {
if (res.code == 200) {
// 为每个诊断项添加默认的诊断医生和时间(如果不存在)
const diagnosisList = res.data.map(item => ({
...item,
diagnosisDoctor: item.diagnosisDoctor || props.patientInfo.practitionerName || props.patientInfo.doctorName || props.patientInfo.physicianName || userStore.name,
diagnosisTime: item.diagnosisTime || new Date().toLocaleString('zh-CN')
}));
// 对获取的数据进行排序
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;
});
form.value.diagnosisList = diagnosisList;
emits('diagnosisSave', false);
console.log(form.value.diagnosisList);
}
});
getTcmDiagnosis({ encounterId: props.patientInfo.encounterId }).then((res) => {
if (res.code == 200) {
if (res.data.illness && res.data.illness.length > 0 && res.data.symptom) {
const newList = [];
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);
console.log(form.value.diagnosisList);
}
});
getTree();
}
init();
function init() {
diagnosisInit().then((res) => {
if (res.code == 200) {
diagnosisOptions.value = res.data.verificationStatusOptions;
}
});
}
function handleImport() {
if (!props.patientInfo || !props.patientInfo.encounterId) {
console.warn('患者就诊信息不完整,无法导入慢性病信息');
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')
},
});
});
}
});
}
}
/**
* 添加子节点
*/
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() {
proxy.$refs.formRef.validate((valid) => {
if (valid) {
if (!allowAdd.value) {
proxy.$modal.msgWarning('请先填写病历');
return;
}
form.value.diagnosisList.push({
showPopover: false,
name: undefined,
verificationStatusEnum: 4,
medTypeCode: '11',
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')
});
if (form.value.diagnosisList.length == 1) {
form.value.diagnosisList[0].maindiseFlag = 1;
}
}
});
}
// 添加中医诊断
function handleAddTcmDiagonsis() {
openAddDiagnosisDialog.value = true;
}
/**
* 删除诊断
*/
/**
* 删除诊断
*/
function handleDeleteDiagnosis(row, index) {
if (row.conditionId) {
delEncounterDiagnosis(row.conditionId).then(() => {
// 不要立即调用getList(),而是从当前列表中移除
form.value.diagnosisList.splice(index, 1);
// 重新排序剩余的项目
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;
});
// 重新分配连续的序号
sortedList.forEach((item, idx) => {
item.diagSrtNo = idx + 1;
});
// 更新列表
form.value.diagnosisList = sortedList.map(item => ({ ...item }));
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() {
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?('data') && 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();
}
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: '11',
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')
});
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>