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

@@ -0,0 +1,621 @@
<template>
<div class="app-container">
<el-row :gutter="10">
<el-form :model="queryParams" ref="queryRef" inline="true">
<el-form-item label="入院病区" prop="wardId" style="width: 240px">
<el-select
v-model="queryParams.wardId"
@change="changeWardLocationId"
filterable
clearable
>
<el-option
v-for="item in initInfoOptions.wardListOptions"
:key="item.id"
:label="item.name"
:value="item.id"
/>
</el-select>
</el-form-item>
<el-form-item label="入院病房" prop="houseId">
<el-select
v-model="queryParams.houseId"
style="width: 240px"
@change="handleQuery"
filterable
clearable
>
<el-option
v-for="item in wardLocationList"
:key="item.id"
:label="item.name"
:value="item.id"
/>
</el-select>
</el-form-item>
<el-form-item label="住院状态" prop="encounterStatus">
<el-select
v-model="queryParams.encounterStatus"
style="width: 240px"
@change="handleQuery"
filterable
clearable
>
<el-option label="全部" value="" />
<el-option
v-for="item in initInfoOptions.encounterStatusOptions"
:key="item.value"
:label="item.label"
:value="item.value"
/>
</el-select>
</el-form-item>
<el-form-item label="床位状态" prop="bedStatus" style="width: 240px">
<el-select v-model="bedStatusFilter" filterable clearable @change="handleQuery">
<el-option label="全部" value="" />
<el-option
v-for="item in initInfoOptions.bedStatusOptions"
:key="item.value"
:label="item.label"
:value="item.value"
/>
</el-select>
</el-form-item>
<el-form-item>
<el-button type="primary" icon="Search" @click="handleQuery">搜索</el-button>
<el-button icon="Refresh" @click="resetQuery">重置</el-button>
</el-form-item>
</el-form>
</el-row>
<el-row :gutter="10">
<el-col :span="4">
<el-card shadow="never">
<template #header>
<div class="card-header">
<span>新入院患者</span>
</div>
</template>
<el-input
v-model="queryParams.searchKey"
placeholder="请输入住院号"
clearable
style="width: 100%; margin-bottom: 10px"
@keyup.enter="handleQuery"
>
<template #append>
<el-button icon="Search" @click="handleQuery" />
</template>
</el-input>
<el-scrollbar height="700px">
<div
v-for="(item, index) in patientList"
:class="item.active ? 'patient-card actived' : 'patient-card'"
:key="item.id"
@click="handleCardClick(item, index)"
@dblclick="handleCardDblClick(item)"
>
<div class="main-info-container">
<div class="name-container">
<!-- 患者姓名 -->
<div class="name" style="max-width: 90px">
<el-text class="name" width="auto">{{ item.patientName || '未知' }}</el-text>
</div>
</div>
<div class="name-container">
<!-- 患者性别/年龄 -->
<div class="age">
<el-text class="name" width="auto">
{{ item.genderEnum_enumText }}/{{ item.age }}/{{ item.priorityEnum_enumText }}
</el-text>
</div>
</div>
<div class="patient-tag" :class="getPatientTagClass(item)">
{{ item.encounterStatus_enumText }}
</div>
</div>
<div style="margin-left: 15px; color: #333; font-size: 14px">
{{ item.contractName }}
</div>
<div class="doctor-parent-line" />
<div class="personal-info-container">
<div class="name-container">
<div class="name">
<el-text class="name" width="auto">入院时间</el-text>
<el-text class="name" width="auto">
{{ item.startTime ? formatDate(item.startTime) : '-' }}
</el-text>
</div>
</div>
</div>
<div class="personal-info-container">
<div class="name-container">
<el-text class="name" width="auto">入院科室</el-text>
<el-text class="name" width="auto">
{{ item.organizationName ? item.organizationName : '-' }}
</el-text>
</div>
</div>
<div class="personal-info-container">
<div class="name-container">
<el-text class="name" width="auto">住院号</el-text>
<el-text class="name" width="auto">
{{ item.busNo ? item.busNo : '-' }}
</el-text>
</div>
</div>
</div>
</el-scrollbar>
</el-card>
</el-col>
<el-col :span="20">
<el-row :gutter="10" class="mb8">
<el-col :span="1.5">
<el-button
type="primary"
plain
icon="Plus"
@click="handleAddFeeItemm"
:disabled="!selectPatient"
>
新增滚费项目
</el-button>
</el-col>
</el-row>
<el-table :data="rollInfoPageList" ref="table" border>
<el-table-column label="滚费项目" prop="definitionName" align="center" />
<el-table-column label="单位" prop="unitCodeName" align="center" />
<el-table-column label="数量" prop="quantity" align="center" />
<el-table-column label="状态" prop="statusEnum_enumText" align="center">
<template #default="scope">
<el-tag v-if="scope.row.statusEnum_enumText === '启用'" type="success">
{{ scope.row.statusEnum_enumText }}
</el-tag>
<el-tag v-else type="warning">
{{ scope.row.statusEnum_enumText }}
</el-tag>
</template>
</el-table-column>
<el-table-column label="操作" align="center">
<template #default="scope">
<el-button
link
type="success"
icon="Edit"
@click="handleEnable(scope.row)"
v-if="scope.row.statusEnum_enumText === '停用'"
>
启用
</el-button>
<el-button
link
type="warning"
icon="Edit"
@click="handleStop(scope.row)"
v-if="scope.row.statusEnum_enumText === '启用'"
>
停用
</el-button>
<el-button link icon="Edit" type="danger" @click="handleDelete(scope.row)">
删除
</el-button>
</template>
</el-table-column>
</el-table>
</el-col>
</el-row>
<el-dialog
title="新增滚费配置"
v-model="dialogVisible"
width="400px"
:before-close="handleClose"
append-to-body
>
<el-form ref="formRef" :model="form" :rules="rules" label-width="100px">
<el-form-item label="滚费项目" prop="instanceId">
<el-select
v-model="form.instanceId"
placeholder="请选择"
filterable
clearable
style="width: 100%"
@change="handleChageInstanceId"
>
<el-option
v-for="item in feeItemOptions"
:key="item.instanceId"
:label="item.instanceName"
:value="item.instanceId"
>
</el-option>
</el-select>
</el-form-item>
<el-form-item label="数量" prop="quantity">
<el-input-number
v-model="form.quantity"
placeholder="请输入数量"
controls-position="right"
style="width: 100%"
/>
</el-form-item>
<el-form-item label="单位" prop="unit">
<el-input v-model="form.unit" placeholder="请输入" disabled style="width: 100%" />
</el-form-item>
</el-form>
<template #footer>
<div class="dialog-footer">
<el-button @click="handleClose"> </el-button>
<el-button type="primary" @click="handleSubmit"> </el-button>
</div>
</template>
</el-dialog>
</div>
</template>
<script setup>
import { onBeforeMount, onMounted, reactive, ref, getCurrentInstance } from 'vue';
import {
getPendingInfo,
getBedInfo,
getInit,
childLocationList,
getPractitionerWard,
getDataSource,
saveInpatientRoll,
getRollInfoPage,
enableRoll,
stopRoll,
deleteRoll,
} from './components/api.js';
import { formatDate } from '@/utils/index';
import { ElMessage } from 'element-plus';
const { proxy } = getCurrentInstance();
const transferInDialogVisible = ref(false);
const dialogVisible = ref(false);
const state = reactive({});
const loading = ref(false);
const total = ref();
const badList = ref([]);
const patientList = ref([]);
const pendingInfo = ref({});
const wardLocationList = ref([]);
const priorityOptions = ref([]);
const initInfoOptions = ref({
encounterStatusOptions: [],
bedStatusOptions: [],
priorityOptions: [],
wardListOptions: [],
});
// 新增床状态筛选字段
const bedStatusFilter = ref('');
onBeforeMount(() => {});
const queryParams = ref({
pageNo: 1,
pageSize: 50,
searchKey: '',
wardId: '',
houseId: '',
encounterStatus: '',
bedStatus: '', // 这个字段现在只用于床位查询,不再用于患者列表查询
});
const formRef = ref(null);
const form = reactive({
instanceId: undefined,
unit: undefined,
quantity: 1,
});
const rules = {
instanceId: [{ required: true, message: '请选择滚费项目', trigger: 'change' }],
quantity: [
{ required: true, message: '请输入数量', trigger: 'blur' },
{ type: 'number', min: 0, message: '数量必须大于等于0', trigger: 'blur' },
],
};
onMounted(() => {
getInit().then((res) => {
initInfoOptions.value = res.data;
priorityOptions.value = res.data.priorityOptions || [];
getList();
});
getPractitionerWard().then((res) => {
queryParams.value.wardId = res[0].id;
initInfoOptions.value.wardListOptions = res;
changeWardLocationId(res[0].id);
});
});
defineExpose({ state });
const feeItemOptions = ref([]);
async function getInitDataSourceOptions() {
const res = await getDataSource();
feeItemOptions.value = res.data;
}
const getList = () => {
getPatientList();
// 床位查询不使用encounterStatus参数只使用基本的查询参数
const bedQueryParams = {
...queryParams.value,
encounterStatus: undefined, // 移除encounterStatus确保不影响床位列表查询
};
getBedInfo(bedQueryParams).then((res) => {
badList.value = res.data.records;
});
};
function handleEnable(row) {
proxy
.$confirm('确定启用吗?', '提示', {
confirmButtonText: '确定',
cancelButtonText: '取消',
type: 'warning',
})
.then(() => {
enableRoll([row.id]).then((res) => {
if (res.code == 200) {
proxy.$modal.msgSuccess('启用成功');
getRollInfoPageList();
}
});
});
}
function handleStop(row) {
proxy
.$confirm('确定停用吗?', '提示', {
confirmButtonText: '确定',
cancelButtonText: '取消',
type: 'warning',
})
.then(() => {
stopRoll([row.id]).then((res) => {
if (res.code == 200) {
proxy.$modal.msgSuccess('停用成功');
getRollInfoPageList();
}
});
});
}
function handleDelete(row) {
proxy
.$confirm('确定删除吗?', '提示', {
confirmButtonText: '确定',
cancelButtonText: '取消',
type: 'warning',
})
.then(() => {
deleteRoll([row.id]).then((res) => {
if (res.code == 200) {
proxy.$modal.msgSuccess('删除成功');
getRollInfoPageList();
}
});
});
}
// 重置查询条件
function resetQuery() {
queryParams.value = {
pageNo: 1,
pageSize: 50,
searchKey: '',
wardId: '',
houseId: '',
encounterStatus: '',
bedStatus: '',
};
bedStatusFilter.value = '';
getList();
}
function changeWardLocationId(id) {
let params = {
locationId: id,
locationForm: 10,
};
queryParams.value.houseId = '';
childLocationList(params).then((res) => {
wardLocationList.value = res;
});
handleQuery();
}
// 获新入院患者列表
function getPatientList() {
// 为患者列表查询创建一个新的参数对象不包含bedStatus
const patientQueryParams = {
...queryParams.value,
bedStatus: undefined, // 移除bedStatus确保不影响患者列表查询
};
getPendingInfo(patientQueryParams).then((res) => {
loading.value = false;
// 为每个患者项初始化 active 属性
patientList.value = res.data.records.map((item) => ({
...item,
active: false,
}));
total.value = res.data.total;
});
}
// 选中患者
const selectPatient = ref(null);
function handleCardClick(item, index) {
// 清除所有项的激活状态
patientList.value.forEach((patient) => {
patient.active = false;
});
// 设置当前项为激活状态
item.active = true;
console.log(item);
selectPatient.value = item;
getRollInfoPageList();
}
function handleChageInstanceId(value) {
form.unit = feeItemOptions.value.find(
(item) => item.instanceId === value
).permittedUnitCode_dictText;
}
function handleClose() {
dialogVisible.value = false;
// 重置表单
form.name = '';
form.unit = '';
form.quantity = 1;
formRef.value?.resetFields();
}
// 获取滚费信息列表
const rollInfoPageList = ref([]);
function getRollInfoPageList() {
const encounterId = selectPatient.value.encounterId;
loading.value = true;
getRollInfoPage(encounterId).then((res) => {
rollInfoPageList.value = res.data;
loading.value = false;
});
}
function handleSubmit() {
formRef.value?.validate((valid) => {
if (valid) {
const param = {
encounterId: selectPatient.value.encounterId,
instanceId: form.instanceId,
quantity: form.quantity,
};
proxy
.$confirm('确认保存吗?', '提示', {
confirmButtonText: '确定',
cancelButtonText: '取消',
type: 'warning',
})
.then(() => {
saveInpatientRoll(param).then((res) => {
ElMessage.success('新增成功');
handleClose();
getRollInfoPageList();
});
})
.catch(() => {});
} else {
ElMessage.warning('请完善表单信息');
}
});
}
// 双击患者卡片事件
function handleCardDblClick(item) {
if (item.encounterStatus == 2) {
ElMessage({
message: '请分配病床!',
type: 'warning',
grouping: true,
showClose: true,
});
} else {
pendingInfo.value = {
...item,
entranceType: 1,
};
transferInDialogVisible.value = true;
}
}
function handleQuery() {
getList();
}
function handleAddFeeItemm() {
dialogVisible.value = true;
getInitDataSourceOptions();
}
function getPatientTagClass(item) {
if (item.encounterStatus == 2) {
return 'blue-tag';
} else if (item.encounterStatus == 5) {
return 'green-tag';
}
return '';
}
</script>
<style lang="scss" scoped>
.patient-card {
width: 100%;
overflow: hidden;
background-color: #fff;
border: 1px solid;
border-color: #eee;
border-radius: 4px;
box-shadow: 0 2px 2px 0 rgba(57.55, 69.04, 86.28, 20%);
margin-bottom: 10px;
cursor: pointer;
transition: all 0.2s ease;
&.actived {
background-color: rgb(7, 155, 140, 5%);
border-color: var(--el-color-primary);
}
&.dragging {
opacity: 0.5;
transform: rotate(5deg);
}
.doctor-parent-line {
margin: 0 16px;
border-bottom: 1px dashed #ddd;
}
.personal-info-container {
display: flex;
align-items: center;
justify-content: space-between;
margin: 8px 0;
padding: 0 16px;
.name-container {
display: flex;
align-items: center;
height: 18px;
.name {
color: #333;
font-size: 14px;
}
.age {
margin-left: 10px;
color: #666;
font-size: 14px;
}
}
}
}
.main-info-container {
display: flex;
align-items: center;
justify-content: space-between;
height: 32px;
margin: 7px 0;
padding: 0 16px;
margin-right: 48px;
position: relative;
.patient-tag {
position: absolute;
top: -7px;
right: -48px;
font-size: 14px;
padding: 2px 8px;
border-radius: 4px;
&.blue-tag {
background-color: #1890ff;
color: white;
}
&.green-tag {
background-color: #52c41a;
color: white;
}
}
}
</style>