Merge remote-tracking branch 'origin/develop' into develop
This commit is contained in:
@@ -130,5 +130,14 @@ public interface IATDManageAppService {
|
||||
* @return 转科筛选选项
|
||||
*/
|
||||
R<?> getTransferOptions();
|
||||
|
||||
/**
|
||||
* 换床 (指定目标床位)
|
||||
*
|
||||
* @param encounterId 住院患者id
|
||||
* @param targetBedId 目标床位id
|
||||
* @return 结果
|
||||
*/
|
||||
R<?> changeBedAssginment(Long encounterId, Long targetBedId);
|
||||
}
|
||||
|
||||
|
||||
@@ -16,6 +16,7 @@ import com.healthlink.his.administration.domain.Encounter;
|
||||
import com.healthlink.his.administration.domain.ChargeItem;
|
||||
import com.healthlink.his.administration.service.IChargeItemService;
|
||||
import com.healthlink.his.administration.domain.EncounterLocation;
|
||||
import com.healthlink.his.administration.domain.Location;
|
||||
import com.healthlink.his.administration.domain.EncounterParticipant;
|
||||
import com.healthlink.his.administration.domain.Location;
|
||||
import com.healthlink.his.administration.domain.Organization;
|
||||
@@ -224,7 +225,7 @@ public class ATDManageAppServiceImpl implements IATDManageAppService {
|
||||
public R<?> getAdmissionBedPage(AdmissionPageParam admissionPageParam, Integer pageNo, Integer pageSize) {
|
||||
// 获取当前登录用户的科室 ID
|
||||
Long currentUserOrgId = SecurityUtils.getLoginUser().getOrgId();
|
||||
|
||||
|
||||
// 构建查询条件
|
||||
QueryWrapper<AdmissionPageParam> queryWrapper
|
||||
= HisQueryUtils.buildQueryWrapper(admissionPageParam, null, null, null);
|
||||
@@ -528,7 +529,7 @@ public class ATDManageAppServiceImpl implements IATDManageAppService {
|
||||
List<EncounterParticipant> savedParticipants = encounterParticipantService.getEncounterParticipantList(encounterId);
|
||||
log.info("保存后查询参与者 - encounterId: {}, 数量: {}", encounterId, savedParticipants.size());
|
||||
for (EncounterParticipant ep : savedParticipants) {
|
||||
log.info("参与者详情 - typeCode: {}, practitionerId: {}, statusEnum: {}",
|
||||
log.info("参与者详情 - typeCode: {}, practitionerId: {}, statusEnum: {}",
|
||||
ep.getTypeCode(), ep.getPractitionerId(), ep.getStatusEnum());
|
||||
}
|
||||
// 更新入院体征(在事务外执行,避免影响参与者数据保存)
|
||||
@@ -983,7 +984,7 @@ public class ATDManageAppServiceImpl implements IATDManageAppService {
|
||||
= ((List<DocStatisticsDto>) docStatisticsAppService.queryByEncounterId(encounterId).getData()).stream()
|
||||
.filter(item -> DocDefinitionEnum.ADMISSION_VITAL_SIGNS.getValue().equals(item.getSource())).toList();
|
||||
List<DocStatisticsDto> list = new ArrayList<>(data);
|
||||
|
||||
|
||||
// 先删除所有已有的入院体征记录(重新保存最新数据)
|
||||
for (DocStatisticsDto existingItem : data) {
|
||||
if (existingItem.getId() != null) {
|
||||
@@ -991,7 +992,7 @@ public class ATDManageAppServiceImpl implements IATDManageAppService {
|
||||
}
|
||||
}
|
||||
list.clear();
|
||||
|
||||
|
||||
map.keySet().forEach(key -> {
|
||||
String value = map.get(key);
|
||||
// 只保存非空值
|
||||
@@ -1188,5 +1189,143 @@ public class ATDManageAppServiceImpl implements IATDManageAppService {
|
||||
|
||||
return R.ok("退床成功");
|
||||
}
|
||||
|
||||
/**
|
||||
* 换床
|
||||
*
|
||||
* @param encounterId 住院患者id
|
||||
* @return 结果
|
||||
*/
|
||||
|
||||
@Override
|
||||
@Transactional(rollbackFor = Exception.class)
|
||||
public R<?> changeBedAssginment(Long encounterId, Long targetBedId) {
|
||||
if (encounterId == null) {
|
||||
return R.fail("换床失败,请选择有效的就诊记录");
|
||||
}
|
||||
if (targetBedId == null) {
|
||||
return R.fail("换床失败,请选择目标床位");
|
||||
}
|
||||
Encounter encounter = encounterService.getById(encounterId);
|
||||
if (encounter == null) {
|
||||
return R.fail("未找到就诊记录");
|
||||
}
|
||||
// 仅已入院状态允许换床
|
||||
if (!EncounterZyStatus.ADMITTED_TO_THE_HOSPITAL.getValue().equals(encounter.getStatusEnum())) {
|
||||
return R.fail("该患者未在科,无法办理换床");
|
||||
}
|
||||
|
||||
// 查询目标床位
|
||||
Location targetBed = locationService.getById(targetBedId);
|
||||
if (targetBed == null) {
|
||||
return R.fail("目标床位不存在");
|
||||
}
|
||||
if (!LocationForm.BED.getValue().equals(targetBed.getFormEnum())) {
|
||||
return R.fail("所选位置不是床位");
|
||||
}
|
||||
|
||||
// 根据目标床位的 busNo 获取其父级房间 (house)
|
||||
String bedBusNo = targetBed.getBusNo();
|
||||
if (bedBusNo == null || !bedBusNo.contains(".")) {
|
||||
return R.fail("目标床位编码异常");
|
||||
}
|
||||
String[] parts = bedBusNo.split("\\.");
|
||||
if (parts.length < 2) {
|
||||
return R.fail("目标床位编码层级异常");
|
||||
}
|
||||
String houseBusNo = parts[0] + "." + parts[1];
|
||||
Location targetHouse = locationService.lambdaQuery()
|
||||
.eq(Location::getBusNo, houseBusNo)
|
||||
.eq(Location::getFormEnum, LocationForm.HOUSE.getValue())
|
||||
.eq(Location::getDeleteFlag, "0")
|
||||
.one();
|
||||
if (targetHouse == null) {
|
||||
return R.fail("未找到目标床位所属的病房");
|
||||
}
|
||||
|
||||
Date now = new Date();
|
||||
|
||||
// 检查目标床位是否已经被占用
|
||||
List<EncounterLocation> occupiedBedLocs = encounterLocationService.lambdaQuery()
|
||||
.eq(EncounterLocation::getLocationId, targetBedId)
|
||||
.eq(EncounterLocation::getFormEnum, LocationForm.BED.getValue())
|
||||
.eq(EncounterLocation::getStatusEnum, EncounterActivityStatus.ACTIVE.getValue())
|
||||
.eq(EncounterLocation::getDeleteFlag, "0")
|
||||
.list();
|
||||
|
||||
if (occupiedBedLocs != null && !occupiedBedLocs.isEmpty()) {
|
||||
// Target bed is occupied! This is a bed swap (床位互换)
|
||||
Long targetEncounterId = occupiedBedLocs.get(0).getEncounterId();
|
||||
Encounter targetEncounter = encounterService.getById(targetEncounterId);
|
||||
if (targetEncounter == null) {
|
||||
return R.fail("目标床位占用患者就诊记录异常");
|
||||
}
|
||||
if (!EncounterZyStatus.ADMITTED_TO_THE_HOSPITAL.getValue().equals(targetEncounter.getStatusEnum())) {
|
||||
return R.fail("目标床位占用患者已不在科,无法办理换床");
|
||||
}
|
||||
|
||||
// 获取当前患者的原床位和原病房
|
||||
List<EncounterLocation> currentBedLocs = encounterLocationService.getEncounterLocationList(encounterId,
|
||||
LocationForm.BED, EncounterActivityStatus.ACTIVE);
|
||||
if (currentBedLocs == null || currentBedLocs.isEmpty()) {
|
||||
return R.fail("当前患者未分配床位,无法进行换床互换");
|
||||
}
|
||||
Long currentBedId = currentBedLocs.get(0).getLocationId();
|
||||
|
||||
List<EncounterLocation> currentHouseLocs = encounterLocationService.getEncounterLocationList(encounterId,
|
||||
LocationForm.HOUSE, EncounterActivityStatus.ACTIVE);
|
||||
if (currentHouseLocs == null || currentHouseLocs.isEmpty()) {
|
||||
return R.fail("当前患者原病房记录不存在");
|
||||
}
|
||||
Long currentHouseId = currentHouseLocs.get(0).getLocationId();
|
||||
|
||||
// 获取被交换患者的原开始时间,保证其床位历史记录连贯性
|
||||
Date targetStartTime = occupiedBedLocs.get(0).getStartTime();
|
||||
if (targetStartTime == null) {
|
||||
targetStartTime = now;
|
||||
}
|
||||
|
||||
// 1. 将两位患者现有的 BED 和 HOUSE 位置状态设为 COMPLETED (false)
|
||||
Integer res1 = encounterLocationService.updateEncounterLocationStatus(encounterId, false);
|
||||
Integer res2 = encounterLocationService.updateEncounterLocationStatus(targetEncounterId, false);
|
||||
if (res1 == 0 || res2 == 0) {
|
||||
throw new RuntimeException("更新原就诊位置状态失败");
|
||||
}
|
||||
|
||||
// 2. 为当前患者创建新位置 (目标病房和目标床位)
|
||||
encounterLocationService.creatEncounterLocation(encounterId, now, targetHouse.getId(), LocationForm.HOUSE.getValue());
|
||||
encounterLocationService.creatEncounterLocation(encounterId, now, targetBedId, LocationForm.BED.getValue());
|
||||
|
||||
// 3. 为被交换患者创建新位置 (当前患者的原病房和原床位)
|
||||
encounterLocationService.creatEncounterLocation(targetEncounterId, targetStartTime, currentHouseId, LocationForm.HOUSE.getValue());
|
||||
encounterLocationService.creatEncounterLocation(targetEncounterId, targetStartTime, currentBedId, LocationForm.BED.getValue());
|
||||
|
||||
return R.ok("床位互换成功");
|
||||
} else {
|
||||
// Target bed is vacant! Normal bed change
|
||||
// 获取当前患者原床位
|
||||
List<EncounterLocation> currentBedLocs = encounterLocationService.getEncounterLocationList(encounterId,
|
||||
LocationForm.BED, EncounterActivityStatus.ACTIVE);
|
||||
|
||||
// 1. 将当前患者现有的 BED 和 HOUSE 位置状态设为 COMPLETED (false)
|
||||
encounterLocationService.updateEncounterLocationStatus(encounterId, false);
|
||||
|
||||
// 2. 将原床位状态更新为空闲 (LocationStatus.IDLE)
|
||||
if (currentBedLocs != null && !currentBedLocs.isEmpty()) {
|
||||
for (EncounterLocation bedLoc : currentBedLocs) {
|
||||
locationService.updateStatusById(bedLoc.getLocationId(), LocationStatus.IDLE.getValue());
|
||||
}
|
||||
}
|
||||
|
||||
// 3. 为当前患者创建新位置 (目标病房和目标床位)
|
||||
encounterLocationService.creatEncounterLocation(encounterId, now, targetHouse.getId(), LocationForm.HOUSE.getValue());
|
||||
encounterLocationService.creatEncounterLocation(encounterId, now, targetBedId, LocationForm.BED.getValue());
|
||||
|
||||
// 4. 将目标床位状态更新为占用 (LocationStatus.OCCUPY)
|
||||
locationService.updateStatusById(targetBedId, LocationStatus.OCCUPY.getValue());
|
||||
|
||||
return R.ok("换床成功");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -14,6 +14,8 @@ import org.springframework.web.bind.annotation.*;
|
||||
|
||||
import jakarta.annotation.Resource;
|
||||
import jakarta.servlet.http.HttpServletRequest;
|
||||
import org.springframework.web.context.request.RequestContextHolder;
|
||||
import org.springframework.web.context.request.ServletRequestAttributes;
|
||||
|
||||
/**
|
||||
* 入出转管理 controller
|
||||
@@ -187,5 +189,19 @@ public class ATDManageController {
|
||||
public R<?> getTransferOptions() {
|
||||
return atdManageAppService.getTransferOptions();
|
||||
}
|
||||
|
||||
/**
|
||||
* 换床
|
||||
*
|
||||
* @param encounterId 住院患者id
|
||||
* @return 结果
|
||||
*/
|
||||
@PutMapping(value = "/change-bed-assignment")
|
||||
public R<?> changeBedAssignment(Long encounterId){
|
||||
HttpServletRequest request = ((ServletRequestAttributes) RequestContextHolder.currentRequestAttributes()).getRequest();
|
||||
String targetBedIdStr = request.getParameter("targetBedId");
|
||||
Long targetBedId = (targetBedIdStr == null || targetBedIdStr.trim().isEmpty()) ? null : Long.valueOf(targetBedIdStr);
|
||||
return atdManageAppService.changeBedAssginment(encounterId, targetBedId);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -113,7 +113,7 @@
|
||||
AND ao_target.delete_flag = '0'
|
||||
WHERE ae.delete_flag = '0'
|
||||
AND ae.class_enum = #{imp}
|
||||
AND ae.status_enum != #{toBeRegistered}
|
||||
AND ae.status_enum IN (2, 3, 5, 6)
|
||||
AND ae.organization_id = #{currentUserOrgId}
|
||||
GROUP BY ae.tenant_id,
|
||||
ae.id,
|
||||
|
||||
@@ -124,11 +124,14 @@ public class EncounterLocationServiceImpl extends ServiceImpl<EncounterLocationM
|
||||
if (isTransfer) {
|
||||
locationForms.add(LocationForm.WARD.getValue());
|
||||
}
|
||||
// 更新状态为已完成
|
||||
// 更新状态为已完成 — 仅针对当前 ACTIVE 且未删除的记录
|
||||
return baseMapper.update(null,
|
||||
new LambdaUpdateWrapper<EncounterLocation>()
|
||||
.set(EncounterLocation::getStatusEnum, EncounterActivityStatus.COMPLETED.getValue())
|
||||
.eq(EncounterLocation::getEncounterId, encounterId).in(EncounterLocation::getFormEnum, locationForms));
|
||||
.eq(EncounterLocation::getEncounterId, encounterId)
|
||||
.in(EncounterLocation::getFormEnum, locationForms)
|
||||
.eq(EncounterLocation::getStatusEnum, EncounterActivityStatus.ACTIVE.getValue())
|
||||
.eq(EncounterLocation::getDeleteFlag, DelFlag.NO.getCode()));
|
||||
}
|
||||
|
||||
/*
|
||||
|
||||
@@ -65,7 +65,7 @@
|
||||
"vue": "^3.5.25",
|
||||
"vue-area-linkage": "^5.1.0",
|
||||
"vue-cropper": "^1.1.1",
|
||||
"vue-i18n": "^11.4.6",
|
||||
"vue-i18n": "^9.14.5",
|
||||
"vue-plugin-hiprint": "^0.0.60",
|
||||
"vue-router": "^4.6.4",
|
||||
"vxe-pc-ui": "^4.14.26",
|
||||
|
||||
@@ -167,6 +167,18 @@ export function cancelBedAssignment(encounterId) {
|
||||
});
|
||||
}
|
||||
|
||||
// 换床/对换
|
||||
export function changeBedAssignment(encounterId, targetBedId) {
|
||||
return request({
|
||||
url: '/nurse-station/atd-manage/change-bed-assignment',
|
||||
method: 'put',
|
||||
params: {
|
||||
encounterId: encounterId,
|
||||
targetBedId: targetBedId,
|
||||
},
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* 获取病区列表(与病区管理页面相同的接口)
|
||||
|
||||
@@ -41,6 +41,14 @@
|
||||
</el-select>
|
||||
</template>
|
||||
<template #extra-buttons>
|
||||
<el-button
|
||||
type="primary"
|
||||
plain
|
||||
style="margin-right: 8px;"
|
||||
@click="handleChangeBed"
|
||||
>
|
||||
换床
|
||||
</el-button>
|
||||
<el-button
|
||||
type="danger"
|
||||
plain
|
||||
@@ -112,6 +120,11 @@
|
||||
@ok-act="handleTransferInOk"
|
||||
/>
|
||||
<SignEntryDialog v-model:visible="signEntryDialogVisible" />
|
||||
<ChangeBedDialog
|
||||
v-model:visible="changeBedDialogVisible"
|
||||
:bad-list="badList"
|
||||
@ok-act="handleTransferInOk"
|
||||
/>
|
||||
</div>
|
||||
</template>
|
||||
<script setup lang="ts">
|
||||
@@ -119,6 +132,7 @@ import Filter from '@/components/TableLayout/Filter.vue';
|
||||
import {computed, onBeforeMount, onMounted, reactive, ref} from 'vue';
|
||||
import TransferInDialog from './transferInDialog.vue';
|
||||
import SignEntryDialog from './signEntryDialog.vue';
|
||||
import ChangeBedDialog from './changeBedDialog.vue';
|
||||
import {childLocationList, getBedInfo, getInit, getPendingInfo, getPractitionerWard, cancelBedAssignment} from './api';
|
||||
import {ElLoading, ElMessage, ElMessageBox} from 'element-plus';
|
||||
import PendingPatientList from '@/components/PendingPatientList/index.vue';
|
||||
@@ -143,6 +157,7 @@ interface InitInfoOptions {
|
||||
|
||||
const transferInDialogVisible = ref(false);
|
||||
const signEntryDialogVisible = ref(false);
|
||||
const changeBedDialogVisible = ref(false);
|
||||
const state = reactive({});
|
||||
const loading = ref(false);
|
||||
const total = ref();
|
||||
@@ -426,6 +441,11 @@ function handleCardDblClick(item: any) {
|
||||
}
|
||||
}
|
||||
|
||||
// 换床操作
|
||||
function handleChangeBed() {
|
||||
changeBedDialogVisible.value = true;
|
||||
}
|
||||
|
||||
// 退床操作 (取消分床)
|
||||
const handleCancelBedAssignment = async () => {
|
||||
const activePatient = patientList.value?.find?.((it) => it?.active);
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
<template>
|
||||
<template>
|
||||
<div class="app-container">
|
||||
<el-form
|
||||
ref="queryRef"
|
||||
@@ -129,7 +129,7 @@
|
||||
<vxe-table
|
||||
v-loading="loading"
|
||||
:data="dataList"
|
||||
height="calc(100vh - 250px)"
|
||||
height="auto"
|
||||
@checkbox-change="handleSelectionChange"
|
||||
>
|
||||
<vxe-column
|
||||
@@ -388,3 +388,21 @@ onMounted(() => {
|
||||
getList();
|
||||
});
|
||||
</script>
|
||||
|
||||
<style lang="scss" scoped>
|
||||
.app-container {
|
||||
height: 100%;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
overflow: hidden;
|
||||
box-sizing: border-box;
|
||||
padding: 20px;
|
||||
}
|
||||
|
||||
.vxe-table {
|
||||
flex: 1;
|
||||
min-height: 0;
|
||||
width: 100%;
|
||||
}
|
||||
</style>
|
||||
|
||||
|
||||
Reference in New Issue
Block a user