docs(release-notes): 添加住院护士站划价功能说明和发版记录

- 新增住院护士站划价服务流程说明文档,详细描述了从参数预处理到结果响应的五大阶段流程
- 包含耗材类医嘱和诊疗活动类医嘱的差异化处理逻辑
- 添加完整的发版内容记录,涵盖新增菜单功能和各模块优化点
- 记录了住院相关功能的新增和门诊业务流程的修复
```
This commit is contained in:
2025-12-25 14:13:14 +08:00
parent 85fcb7c2e2
commit abc0674531
920 changed files with 107068 additions and 14495 deletions

View File

@@ -101,9 +101,9 @@
>
<el-option
v-for="item in diagnosisListOption"
:key="item.id"
:label="item.name"
:value="item.id"
:key="item.definitionId"
:label="item.name + '--' + item.ybNo"
:value="item.definitionId"
/>
</el-select>
</el-form-item>
@@ -432,7 +432,7 @@ import { computed, onMounted, ref } from 'vue';
import { reactive } from 'vue';
// import { useModal, useDict } from '@/hooks';
import { parseTime, formatNumber } from '@/utils/his';
import { queryYbCatalogue, getDiagnosisList } from './api';
import { queryYbCatalogue, getDiagnosisListEle } from './api';
import { debounce } from 'lodash-es';
import {
@@ -565,7 +565,7 @@ const unitMap = ref({
function getInit(searchKey) {
if(searchKey) {
getDiagnosisList(searchKey).then(res => {
getDiagnosisListEle(searchKey,infoForm.encounterId).then(res => {
diagnosisListOption.value = res.data
})
}

View File

@@ -150,12 +150,12 @@
</el-col>
<el-col :span="12">
<el-form-item label="入院诊断" prop="diagnosisDefinitionId">
<el-select
<!-- <el-select
v-model="submitForm.diagnosisDefinitionId"
placeholder="诊断"
clearable
filterable
remote
remote
:remote-method="getDiagnosisInfo"
style="width: 400px"
>
@@ -166,7 +166,10 @@
:value="item.id"
@click="handleDiagnosisChange(item)"
/>
</el-select>
</el-select> -->
<el-input v-model="props.mainDiagnosis.name" disabled style="width: 400px" />
<!-- 隐藏存储ID的字段 -->
<input type="hidden" v-model="submitForm.diagnosisDefinitionId" />
</el-form-item>
</el-col>
</el-row>
@@ -179,7 +182,7 @@
</template>
</el-dialog>
</template>
<script setup>
import {
getInit,
@@ -206,6 +209,7 @@ const props = defineProps({
type: String,
default: '',
},
mainDiagnosis: { type: Object, default: null },
});
const emit = defineEmits(['close']);
@@ -244,9 +248,17 @@ const rules = reactive({
});
function openDialog() {
console.log('orgId==========>', props.patientInfo.orgId);
getOrgList().then((res) => {
organization.value = res.data.records;
// organization.value = res.data.records;
organization.value = res.data.records[0].children.filter(
(record) => record.typeEnum === 2 && record.classEnum === 2
);
console.log('organization==========>', organization.value);
submitForm.inHospitalOrgId =
organization.value.find((item) => item.id === props.patientInfo.orgId)?.id || '';
});
// wardList().then((res) => {
// wardListOptions.value = res.data;
// });
@@ -256,6 +268,14 @@ function openDialog() {
});
console.log(props.patientInfo, 'patientInfo');
getDiagnosisInfo(undefined);
console.log(props.mainDiagnosis, 'mainDiagnosis');
if (props.mainDiagnosis) {
submitForm.diagnosisDefinitionId = props.mainDiagnosis.definitionId;
diagnosisDefinitionId = props.mainDiagnosis.definitionId;
diagnosisYbNo = props.mainDiagnosis.ybNo || '';
submitForm.medTypeCode = props.mainDiagnosis.medTypeCode;
diagnosisDefinitionList.value = [props.mainDiagnosis];
}
}
function getDiagnosisInfo(value) {
@@ -333,4 +353,4 @@ function close() {
.patInfo-value {
width: 100px;
}
</style>
</style>

View File

@@ -0,0 +1,195 @@
<!-- consumableDialog.vue -->
<template>
<el-dialog
v-model="dialogVisible"
title="皮试检查"
width="700px"
:close-on-click-modal="false"
:before-close="handleClose"
>
<div class="consumable-dialog">
<div class="dialog-header">
<el-alert
title="下列药品需要执行皮试项目,请确认,点击确定将自动添加皮试检查项目到医嘱列表"
type="warning"
show-icon
:closable="false"
/>
</div>
<div class="table-container">
<el-table
ref="consumableTableRef"
:data="consumableList"
row-key="orderDefinitionId"
border
style="width: 100%"
>
<el-table-column type="selection" width="50" align="center" />
<el-table-column prop="adviceName" align="center" label="项目名称" />
<el-table-column prop="unitCodeName" label="单位" align="center" width="80">
<template #default="scope">
{{ scope.row.unitCodeName || '-' }}
</template>
</el-table-column>
<el-table-column label="执行次数" align="center" width="120">
<template #default="scope">
{{ '1' }}
</template>
</el-table-column>
<el-table-column label="操作" width="80" align="center" fixed="right">
<template #default="scope">
<el-button type="danger" link size="small" @click="handleDeleteRow(scope.row)">
删除
</el-button>
</template>
</el-table-column>
</el-table>
</div>
<!-- 下次不再提示复选框 -->
<div class="dont-show-again">
<!-- <el-checkbox v-model="dontShowAgain" @change="handleDontShowAgainChange">
下次不再提示
</el-checkbox> -->
</div>
</div>
<template #footer>
<span class="dialog-footer">
<el-button @click="handleClose">取消</el-button>
<el-button ref="submitRef" type="primary" @click="handleSubmit">确定</el-button>
</span>
</template>
</el-dialog>
</template>
<script setup>
import { ElMessageBox, ElMessage } from 'element-plus';
import { ref, nextTick, onBeforeUnmount } from 'vue';
import useUserStore from '@/store/modules/user';
const dialogVisible = ref(false);
const consumableList = ref([]);
const consumableTableRef = ref();
const submitRef = ref();
const dontShowAgain = ref(false); // 下次不再提示的状态
const userStore = useUserStore();
// 定义事件
const emit = defineEmits(['submit']);
// 键盘事件处理函数
const handleKeyDown = (event) => {
// 检查是否按下了回车键
if (event.key === 'Enter' && dialogVisible.value) {
event.preventDefault();
handleSubmit();
}
};
// 打开弹窗方法
const open = (data) => {
consumableList.value = data;
dialogVisible.value = true;
// 默认全选
nextTick(() => {
if (consumableTableRef.value) {
consumableList.value.forEach((row) => {
consumableTableRef.value.toggleRowSelection(row, true);
});
}
// 注册键盘事件监听器
document.addEventListener('keydown', handleKeyDown);
});
};
// 关闭弹窗方法
const handleClose = () => {
// 移除键盘事件监听器
document.removeEventListener('keydown', handleKeyDown);
dialogVisible.value = false;
consumableList.value = [];
};
// 页面卸载前清理事件监听器
onBeforeUnmount(() => {
document.removeEventListener('keydown', handleKeyDown);
});
// 删除行处理
const handleDeleteRow = (row) => {
ElMessageBox.confirm(`确定要删除 "${row.orderDefinitionName}" 吗?`, '提示', {
confirmButtonText: '确定',
cancelButtonText: '取消',
type: 'warning',
}).then(() => {
const index = consumableList.value.findIndex(
(item) => item.orderDefinitionId === row.orderDefinitionId
);
if (index > -1) {
consumableList.value.splice(index, 1);
}
});
};
// 提交处理
const handleSubmit = () => {
const selectedRows = consumableTableRef.value.getSelectionRows();
// 保存到本地存储
// localStorage.setItem('doctor' + userStore.id.toString(), dontShowAgain.value);
if (selectedRows.length === 0) {
ElMessage.warning('请至少选择一项');
return;
}
// 发送事件给父组件
emit('submit', selectedRows);
// 关闭弹窗并清理事件监听器
document.removeEventListener('keydown', handleKeyDown);
dialogVisible.value = false;
consumableList.value = [];
};
// 暴露方法给父组件
defineExpose({
open,
close: handleClose,
});
</script>
<style lang="scss" scoped>
.consumable-dialog {
.dialog-header {
margin-bottom: 20px;
}
.table-container {
margin-bottom: 20px;
}
.dont-show-again {
margin-top: 10px;
text-align: left;
}
.dialog-footer-summary {
text-align: right;
.summary-text {
font-size: 14px;
color: #606266;
.total-amount {
font-size: 16px;
font-weight: bold;
color: #e64545;
}
}
}
}
.dialog-footer {
display: flex;
justify-content: flex-end;
align-items: center;
}
</style>

View File

@@ -0,0 +1,243 @@
<template>
<div class="report-container">
<div class="report-section">
<div class="report-title">
<span>检查报告</span>
<el-icon
class="report-refresh-icon"
:class="{ 'is-loading': loadingCheck }"
@click="handleRefreshCheck"
>
<Refresh />
</el-icon>
</div>
<div class="report-table-wrapper">
<el-table
v-loading="loadingCheck"
:data="checkReportList"
border
size="small"
height="100%"
style="width: 100%"
>
<el-table-column type="index" label="序号" width="60" align="center" />
<el-table-column prop="adviceName" label="报告名称" width="140" />
<el-table-column prop="reportNo" label="报告号" width="140" />
<el-table-column label="链接" min-width="140">
<template #default="scope">
<a
v-if="scope.row.requestUrl"
class="report-link"
:href="scope.row.requestUrl"
target="_blank"
rel="noopener noreferrer"
>
查看报告
</a>
<span v-else class="report-link-disabled">暂无链接</span>
</template>
</el-table-column>
</el-table>
</div>
</div>
<div class="report-section">
<div class="report-title">
<span>检验报告</span>
<el-icon
class="report-refresh-icon"
:class="{ 'is-loading': loadingInspection }"
@click="handleRefreshInspection"
>
<Refresh />
</el-icon>
</div>
<div class="report-table-wrapper">
<el-table
v-loading="loadingInspection"
:data="inspectionReportList"
border
size="small"
height="100%"
style="width: 100%"
>
<el-table-column type="index" label="序号" width="60" align="center" />
<el-table-column prop="adviceName" label="报告名称" width="140" />
<el-table-column prop="reportNo" label="报告号" width="140" />
<el-table-column label="链接" min-width="140">
<template #default="scope">
<a
v-if="scope.row.requestUrl"
class="report-link"
:href="scope.row.requestUrl"
target="_blank"
rel="noopener noreferrer"
>
查看报告
</a>
<span v-else class="report-link-disabled">暂无链接</span>
</template>
</el-table-column>
</el-table>
</div>
</div>
</div>
</template>
<script setup>
import { getCurrentInstance, ref, watch } from 'vue';
import { Refresh } from '@element-plus/icons-vue';
import { getProofResult, getTestResult } from './api';
const { proxy } = getCurrentInstance();
const props = defineProps({
patientInfo: {
type: Object,
required: true,
},
});
const checkReportList = ref([]);
const inspectionReportList = ref([]);
const loadingCheck = ref(false);
const loadingInspection = ref(false);
const fetchCheckReport = async () => {
if (!props.patientInfo?.encounterId) return;
const res = await getTestResult({ encounterId: props.patientInfo.encounterId });
if (res.code === 200 && res.data) {
const raw = res.data?.records || res.data;
const list = Array.isArray(raw) ? raw : [raw];
checkReportList.value = list.filter(Boolean).map((item) => ({
reportNo: item.busNo,
requestUrl: item.requestUrl,
adviceName: item.adviceName,
_raw: item,
}));
} else {
checkReportList.value = [];
}
};
const fetchInspectionReport = async () => {
if (!props.patientInfo?.encounterId) return;
const res = await getProofResult({ encounterId: props.patientInfo.encounterId });
if (res.code === 200 && res.data) {
const raw = res.data?.records || res.data;
const list = Array.isArray(raw) ? raw : [raw];
inspectionReportList.value = list.filter(Boolean).map((item) => ({
reportNo: item.busNo,
requestUrl: item.requestUrl,
adviceName: item.adviceName,
_raw: item,
}));
} else {
inspectionReportList.value = [];
}
};
const fetchAll = async () => {
if (!props.patientInfo?.encounterId) {
checkReportList.value = [];
inspectionReportList.value = [];
loadingCheck.value = false;
loadingInspection.value = false;
return;
}
loadingCheck.value = true;
loadingInspection.value = true;
try {
await Promise.all([fetchCheckReport(), fetchInspectionReport()]);
} catch (e) {
proxy.$modal?.msgError?.(e.message || '查询报告失败');
} finally {
loadingCheck.value = false;
loadingInspection.value = false;
}
};
const handleRefreshCheck = async () => {
if (loadingCheck.value || !props.patientInfo?.encounterId) return;
loadingCheck.value = true;
try {
await fetchCheckReport();
} finally {
loadingCheck.value = false;
}
};
const handleRefreshInspection = async () => {
if (loadingInspection.value || !props.patientInfo?.encounterId) return;
loadingInspection.value = true;
try {
await fetchInspectionReport();
} finally {
loadingInspection.value = false;
}
};
watch(
() => props.patientInfo?.encounterId,
(val) => {
if (val) {
fetchAll();
} else {
checkReportList.value = [];
inspectionReportList.value = [];
}
},
{ immediate: true }
);
</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;
max-height: 55%;
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;
}
.report-table-wrapper {
flex: 1;
min-height: 0;
overflow: auto;
}
.report-refresh-icon {
cursor: pointer;
color: #909399;
transition: color 0.2s;
}
.report-refresh-icon:hover {
color: #409eff;
}
.report-link {
color: #409eff;
cursor: pointer;
text-decoration: underline;
}
.report-link-disabled {
color: #c0c4cc;
}
</style>

View File

@@ -0,0 +1,259 @@
const formData = reactive({
//医院信息
hospitalInfo: {
//组织机构代码
medins_orgcode: '',
//医疗付款方式
medfee_paymtd_code: '',
},
//患者信息
patientInfo: {
// 健康卡号
healthCardNo: '',
// 患者姓名
patient_name: '',
// 患者性别
gend: '',
// 出生日期
brdy: '',
// 年龄
age: '',
// 国籍
ntly: '中国',
// 籍贯
napl: '',
// 民族
naty: '1',
// 身份证号
certno: '',
// 户口住址
resd_addr: '',
// 工作单位地址
empr_addr: '',
// 联系人姓名
coner_name: '',
// 关系
coner_rlts_code: '',
// 联系人地址
coner_addr: '',
// 联系人电话
coner_tel: '',
},
// 住院信息
admission: {
// 第几次住院
patn_ipt_cnt: 1,
// 住院号
ipt_no: '',
// 病案号
medcasno: '',
// 入院途径
adm_way_code: '',
// 入院时间
adm_time: '',
// 入院科室
adm_dept_name: '',
// 病房
adm_ward: '',
// 确诊日期
adm_date: '',
// 出院时间
dscg_date: '',
// 出院科室
dscg_caty: '',
// 病房
dscg_ward: '',
// 实际住院天数
act_ipt_days: '',
},
// 诊断信息
diagnosis: {
// 主要诊断
mainDiagnosis: '',
// 其他诊断
otherDiagnosis: '',
},
// 诊断信息
diagnosisList: [],
// 医疗信息
medicalInfo: {
// 是否输血
bloodTransfusion: '',
// 血型
abo_code: '',
// rh类型
rh_code: '',
// 药物过敏史
die_autp_flag: '',
},
// 医师信息
doctorInfo: {
// 科主任
deptdrt_name: '',
// 副主任
chfdr_name: '',
// 主治医师
chfpdr_name: '',
// 住院医师
ipt_dr_name: '',
// 责任护士
resp_nurs_name: '',
// 住院总医师
chiefResident: '',
// 实习医师
intn_dr_name: '',
// 病案质量
medcas_qlt_code: '',
// 编码员
codr_name: '',
// 控制日期
qltctrl_date: '',
},
// 病案首页2
medicalSecond: {
// 手术方式
surgeryType: '',
// 离院方式
dscg_way: '',
// 31天是否计划出院
dscg_31days_rinp_flag: '',
// 目的
dscg_31days_rinp_pup: '',
//昏迷时间---入院前
brn_damg_bfadm_coma_dura: '',
//昏迷时间---入院后
brn_damg_afadm_coma_dura: '',
// 肿瘤分期
tumorStaging: '',
// T
tumor_T: '',
// N
tumor_N: '',
// M
tumor_M: '',
// 判断依据
judgmentBase: '',
// 分化程度
bkup_deg_code: '',
// 临床路径
enterPath: '',
// 变异
mutation: '',
// 退出路径
outPath: '',
// 特级护理
nursingLevel_spec: '',
// 1级护理
nursingLevel_1: '',
// 2级护理
nursingLevel_2: '',
// 3级护理
nursingLevel_3: '',
// 呼吸机使用
use_vent_flag: '',
// 有创呼吸机使用小时
vent_used_dura: '',
// 手术表
surgery_tableData: [],
},
// 病案首页3
// 住院费用
hospitalization: {
// 总费用
medfee_sumamt: '',
// 自付金额
selfpay_amt: '',
},
// 综合医疗服务类
medicalServices: {
// 一般医疗服务类
ordn_med_servfee: '',
// 一般治疗操作费
ordn_trt_oprt_fee: '',
// 护理费
nurs_fee: '',
// 其他费用
com_med_serv_oth_fee: '',
},
// 诊断类
diagnosisClass: {
// 病理诊断
palg_diag_fee: '',
// 实验室诊断
lab_diag_fee: '',
// 影像学诊断
rdhy_diag_fee: '',
// 临床诊断
clnc_dise_fee: '',
},
// 治疗类
treatmentClass: {
// 非手术治疗项目费
nsrgtrt_item_fee: '',
// 临床物理治疗
clnc_phys_trt_fee: '',
// 手术治疗费
rgtrt_trt_fee: '',
// 麻醉费
anst_fee: '',
// 手术费
rgtrt_fee: '',
},
// 康复类
recoveryClass: {
// 康复费
rhab_fee: '',
},
// 中医类
TCMClass: {
// 中医治疗费
tcm_trt_fee: '',
},
// 西药类
WesternClass: {
// 西药费
wm_fee: '',
// 抗菌药物费
abtl_medn_fee: '',
},
// 中药类
chineseClass: {
//中成药
tcmpat_fee: '',
// 中草药
tcmherb_fee: '',
},
// 血液和血液制品类
bloodClass: {
// 血费
blo_fee: '',
// 蛋白类制品费
albu_fee: '',
// 球蛋白制品费
glon_fee: '',
// 凝血因子制品费
clotfac_fee: '',
// 细胞因子制品费
cyki_fee: '',
},
// 耗材类
consumablesClass: {
// 检查用一次性医用材料费
exam_dspo_matl_fee: '',
// 治疗用一次性医用材料费
trt_dspo_matl_fee: '',
// 手术用一次性医用材料费
oprn_dspo_matl_fee: '',
},
// 其他类
otherClass: {
// 其他费用
oth_fee: '',
},
// 其他诊断及手术附加页
other_tableData: [],
// 手术操作数组
surgery_tableData: [],
});
export default formData;