package cn.lihu.jh.module.ecg.service.queue; import java.util.*; import java.util.concurrent.*; import javax.annotation.Resource; import cn.lihu.jh.module.ecg.Utils; import cn.lihu.jh.module.ecg.controller.admin.room.vo.MonitorInfoVO; import cn.lihu.jh.module.ecg.dal.dataobject.checktype.CheckTypeDO; import cn.lihu.jh.module.ecg.dal.dataobject.devrent.DevRentDO; import cn.lihu.jh.module.ecg.dal.mysql.call.CallMapper; import cn.lihu.jh.module.ecg.dal.mysql.devrent.DevRentMapper; import cn.lihu.jh.module.ecg.enums.DevRentStateEnum; import cn.lihu.jh.module.system.api.oauth2.OAuth2TokenApi; import lombok.extern.slf4j.Slf4j; import org.springframework.stereotype.Service; import org.springframework.transaction.annotation.Transactional; import org.springframework.validation.annotation.Validated; import cn.lihu.jh.module.ecg.dal.dataobject.room.RoomDO; import cn.lihu.jh.framework.common.exception.ErrorCode; import cn.lihu.jh.framework.common.pojo.CommonResult; import cn.lihu.jh.module.ecg.controller.admin.room.vo.RoomRespVO; import cn.lihu.jh.module.ecg.dal.dataobject.queue.BedQueueStatisticDO; import cn.lihu.jh.module.ecg.dal.mysql.room.RoomMapper; import cn.lihu.jh.module.ecg.enums.QueueStatusEnum; import cn.lihu.jh.module.ecg.controller.admin.queue.vo.*; import cn.lihu.jh.module.ecg.dal.dataobject.queue.QueueDO; import cn.lihu.jh.framework.common.pojo.PageResult; import cn.lihu.jh.framework.common.util.object.BeanUtils; import cn.lihu.jh.module.ecg.dal.mysql.queue.QueueMapper; import static cn.lihu.jh.module.ecg.enums.ErrorCodeConstants.*; import static cn.lihu.jh.framework.common.exception.util.ServiceExceptionUtil.exception; import static cn.lihu.jh.framework.common.pojo.CommonResult.error; import static cn.lihu.jh.framework.common.pojo.CommonResult.success; /** * 排队 Service 实现类 * * @author 芋道源码 */ @Service @Validated @Slf4j public class QueueServiceImpl implements QueueService { @Resource QueueServiceTxFunctions queueServiceTxFunctions; @Resource private OAuth2TokenApi oAuth2TokenApi; @Resource private QueueMapper queueMapper; @Resource private RoomMapper roomMapper; @Resource private CallMapper callMapper; @Resource private DevRentMapper devRentMapper; ExecutorService singleThreadExecutor = Executors.newSingleThreadExecutor(); ConcurrentHashMap mapRoomBed = new ConcurrentHashMap<>(); @Override public Integer createqueue(QueueSaveReqVO createReqVO) { // 插入 QueueDO queue = BeanUtils.toBean(createReqVO, QueueDO.class); queueMapper.insert(queue); // 返回 return queue.getId(); } @Override public void updatequeue(QueueSaveReqVO updateReqVO) { // 校验存在 validatequeueExists(updateReqVO.getId()); // 更新 QueueDO updateObj = BeanUtils.toBean(updateReqVO, QueueDO.class); queueMapper.updateById(updateObj); } @Override public void deletequeue(Integer id) { // 校验存在 validatequeueExists(id); // 删除 queueMapper.deleteById(id); } @Override public ErrorCode startBedOpen(Long roomId, String roomName, String bedNo) { Future future = singleThreadExecutor.submit( new BedOpenCallable(queueServiceTxFunctions, roomId, roomName, bedNo)); try { ErrorCode ret = future.get(); return ret; } catch (InterruptedException e) { e.printStackTrace(); } catch (ExecutionException e) { e.printStackTrace(); } System.out.println("startBedOpen ========"); return ECG_INNER_ERROR; } @Override public ErrorCode startBedClose(Long roomId, String bedNo) { Future future = singleThreadExecutor.submit( new BedCloseCallable(queueServiceTxFunctions, roomId, bedNo)); try { ErrorCode ret = future.get(); return ret; } catch (InterruptedException e) { e.printStackTrace(); } catch (ExecutionException e) { e.printStackTrace(); } System.out.println("startBedClose ========"); return ECG_INNER_ERROR; } @Override public ErrorCode startBedDoctorPause(Long roomId, String bedNo, Long docId, String docName) { Future future = singleThreadExecutor.submit( new BedDoctorPauseCallable(queueServiceTxFunctions, roomId, bedNo, docId, docName) ); try { ErrorCode ret = future.get(); return ret; } catch (InterruptedException e) { e.printStackTrace(); } catch (ExecutionException e) { e.printStackTrace(); } System.out.println("startBedDoctorPause ========"); return ECG_INNER_ERROR; } @Override public ErrorCode startBedDoctorResume(Long roomId, String bedNo, Long docId, String docName) { Future future = singleThreadExecutor.submit( new BedDoctorResumeCallable(queueServiceTxFunctions, roomId, bedNo, docId, docName) ); try { ErrorCode ret = future.get(); return ret; } catch (InterruptedException e) { e.printStackTrace(); } catch (ExecutionException e) { e.printStackTrace(); } System.out.println("startBedDoctorResume ========"); return ECG_INNER_ERROR; } @Override public ErrorCode startBedDoctorOn(Long roomId, String bedNo, Long docId, String docName) { Future future = singleThreadExecutor.submit( new BedDoctorOnCallable(queueServiceTxFunctions, roomId, bedNo, docId, docName) ); try { ErrorCode ret = future.get(); return ret; } catch (InterruptedException e) { e.printStackTrace(); } catch (ExecutionException e) { e.printStackTrace(); } System.out.println("startBedDoctorOn ========"); return ECG_INNER_ERROR; } @Override public ErrorCode startBedDoctorOff(Long roomId, String bedNo, Long docId, String docName) { Future future = singleThreadExecutor.submit( new BedDoctorOffCallable(queueServiceTxFunctions, roomId, bedNo, docId, docName) ); try { ErrorCode ret = future.get(); return ret; } catch (InterruptedException e) { e.printStackTrace(); } catch (ExecutionException e) { e.printStackTrace(); } //System.out.println("startBedDoctorOff ========"); return ECG_INNER_ERROR; } @Override public ErrorCode startNextPatient(Long roomId, String bedNo) { Future future = singleThreadExecutor.submit( new BedDoctorNextPatientCallable(queueServiceTxFunctions, roomId, bedNo) ); try { ErrorCode ret = future.get(); return ret; } catch (InterruptedException e) { e.printStackTrace(); } catch (ExecutionException e) { e.printStackTrace(); } //System.out.println("startNextPatient ========"); return ECG_INNER_ERROR; } @Override public ErrorCode startNextInstallPatient(Long roomId, String bedNo) { Future future = singleThreadExecutor.submit( new BedDoctorNextInstallPatientCallable(queueServiceTxFunctions, roomId, bedNo) ); try { ErrorCode ret = future.get(); return ret; } catch (InterruptedException e) { e.printStackTrace(); } catch (ExecutionException e) { e.printStackTrace(); } System.out.println("startNextInstallPatient ========"); return ECG_INNER_ERROR; } @Override public void startHurryUpOneBed(Long roomId, String bedNo) { singleThreadExecutor.execute( () -> { queueServiceTxFunctions.hurryupOneBed(roomId, bedNo); }); } @Override public void startHurryUpOneCheckType(Integer checkType) { singleThreadExecutor.execute( () -> { queueServiceTxFunctions.hurryupOneCheckType( checkType ); }); } @Override public void startBedReload() { singleThreadExecutor.execute( () -> { queueServiceTxFunctions.bedReload(); queueServiceTxFunctions.hurryupAllBed(); queueServiceTxFunctions.monitorInfo(); }); } @Override public void startResetRoom(Boolean needCloseBed) { singleThreadExecutor.execute( () -> { queueServiceTxFunctions.resetRoom(needCloseBed); queueServiceTxFunctions.bedReload(); queueServiceTxFunctions.monitorInfo(); }); } @Override public MonitorInfoVO getMonitorInfo() { return queueServiceTxFunctions.getMonitorInfo(); } @Override public CommonResult getRoom(Long roomId, String bedNo, Long docId) { RoomDO roomDO = roomMapper.getRoomByRoomBedDoc(roomId, bedNo, docId); if (null == roomDO) { return error(ROOM_NOT_SIT); } BedQueueBO bedQueueBO = queueServiceTxFunctions.getBedQueueBO(roomId, bedNo); if (null == bedQueueBO) { log.error("getRoom mapBedVsQueue DONOT existed. " + roomId + " " + bedNo); return error(QUEUE_BED_NOT_EXIST); } RoomRespVO roomRespVO = BeanUtils.toBean(roomDO, RoomRespVO.class); return success(roomRespVO); } private void validatequeueExists(Integer id) { if (queueMapper.selectById(id) == null) { throw exception(QUEUE_NOT_EXISTS); } } @Override public QueueDO getqueue(Integer id) { return queueMapper.selectById(id); } @Override public PageResult getqueuePage(QueuePageReqVO pageReqVO) { return queueMapper.selectPage(pageReqVO); } /** * 预约确认后的排队 * @param queueSaveReqVO */ @Override @Transactional public void queue(QueueSaveReqVO queueSaveReqVO) { queueSaveReqVO.setStatus(QueueStatusEnum.WAITING.getStatus()); //默认状态: 排队中 // 处理 检查项目.亲和性 逻辑 CheckTypeDO checkTypeDO = queueServiceTxFunctions.getCheckTypeItem( queueSaveReqVO.getBookCheckType() ); if ( checkTypeDO.getAffinityCheckTypes().length > 0) { List affinityItems = queueMapper.getCurPatGivenCheckTypes(queueSaveReqVO.getPatId(), checkTypeDO.getAffinityCheckTypes()); for (int i=0; i < affinityItems.size(); i++) { QueueDO queueItem = affinityItems.get(i); if (QueueStatusEnum.READY.getStatus() == queueItem.getStatus() || QueueStatusEnum.ONSTAGE.getStatus() == queueItem.getStatus()) { queueSaveReqVO.setStatus(QueueStatusEnum.AFFINITY_WAITING.getStatus()); //改变 排队状态 queueSaveReqVO.setRoomId(queueItem.getRoomId()); queueSaveReqVO.setRoomName(queueItem.getRoomName()); queueSaveReqVO.setBedNo(queueItem.getBedNo()); queueSaveReqVO.setSeqNum(queueItem.getSeqNum()); break; } } } QueueDO queue = BeanUtils.toBean(queueSaveReqVO, QueueDO.class); queueMapper.insert(queue); DevRentDO devRent = BeanUtils.toBean(queueSaveReqVO, DevRentDO.class); devRent.setState( DevRentStateEnum.FREE.getState() ); devRent.setPatDetails( queueSaveReqVO.getPatDetails() ); devRent.setCheckType( queueSaveReqVO.getBookCheckType() ); devRentMapper.insert(devRent); startHurryUpOneCheckType( queue.getBookCheckType() ); } // 常规检查 叫号 @Override public void finishNextPatient(Long roomId, String bedNo) { // 从 DB 把 就诊中的人 设置为就诊完成 //Integer ret = queueMapper.updateBedQueueStatus(roomId, bedNo, // QueueStatusEnum.ONSTAGE.getStatus(), QueueStatusEnum.FINISH.getStatus()); // 从 DB 检查 该工位 是否有 [就诊中] 人员,若有就.放弃取下一位 List queueStatusList = new ArrayList<>(); queueStatusList.add(QueueStatusEnum.ONSTAGE.getStatus()); Integer num = queueMapper.bedQueueStatisticByStatus(roomId, bedNo, queueStatusList); if ( num != null && num > 0) return; startNextPatient(roomId, bedNo); } // 领用 叫号 @Override public void finishReceiveNextPatient(Long roomId, String bedNo) { // 从 DB 检查 该工位 是否有 [就诊中] 人员,若有就.放弃取下一位 List queueStatusList = new ArrayList<>(); queueStatusList.add(QueueStatusEnum.ONSTAGE.getStatus()); Integer num = queueMapper.bedQueueStatisticByStatus(roomId, bedNo, queueStatusList); if ( num != null && num > 0) return; startNextPatient(roomId, bedNo); } // 装机 叫号 @Override public void finishInstallNextPatient(Long roomId, String bedNo) { // 从 DB 检查 该工位 是否有 [安装中] 人员,若有就.放弃取下一位 List queueStatusList = new ArrayList<>(); queueStatusList.add(QueueStatusEnum.INSTALLING.getStatus()); Integer num = queueMapper.bedQueueStatisticByStatus(roomId, bedNo, queueStatusList); if ( num != null && num > 0) return; startNextInstallPatient(roomId, bedNo); } public void passNextPatient(Long roomId, String bedNo) { // 从 DB 把 就诊中的人 设置为过号 Integer ret = queueMapper.updateBedQueueStatus(roomId, bedNo, QueueStatusEnum.ONSTAGE.getStatus(), QueueStatusEnum.PASSED.getStatus()); startNextPatient(roomId, bedNo); } @Override public void passInstallNextPatient(Long roomId, String bedNo) { // 从 DB 把 [安装中]的人 设置为 [过号-安装] Integer ret = queueMapper.updateBedQueueStatus(roomId, bedNo, QueueStatusEnum.INSTALLING.getStatus(), QueueStatusEnum.PASSED_INSTALL.getStatus()); startNextPatient(roomId, bedNo); } public List getBedQueueByStatus(Long roomId, String bedNo, List statusList) { List queueDOList = queueMapper.getBedQueueByStatus(roomId, bedNo, statusList); return queueDOList; } @Override public List getRoomQueueByStatus(Long roomId, List statusList) { List queueDOList = queueMapper.getRoomQueueByStatus(roomId, statusList); return queueDOList; } // 常规检查 医生界面的统计信息 public PatientStatisticVO getPatientStatistic(Long roomId, String bedNo) { PatientStatisticVO patientStatisticVO = new PatientStatisticVO(); List bedQueueStatisticDOList = queueMapper.bedQueueStatistic(roomId, bedNo); bedQueueStatisticDOList.forEach(item -> { if (QueueStatusEnum.READY.getStatus() == item.getStatus()) { patientStatisticVO.setReadyNum(item.getTotalInStatus()); } else if (QueueStatusEnum.FINISH.getStatus() == item.getStatus()) { patientStatisticVO.setFinishedNum(item.getTotalInStatus()); } else if (QueueStatusEnum.PASSED.getStatus() == item.getStatus()) { patientStatisticVO.setPassedNum(item.getTotalInStatus()); } }); // 统计 该工位类型的【排队中】人员数量 RoomDO roomDO = getRoomDO(roomId, bedNo); Integer[] checkTypes = roomDO.getCheckTypes(); List statusList = new ArrayList<>(); statusList.add(QueueStatusEnum.WAITING.getStatus()); Integer num = queueMapper.checkTypeAndStatusStatistic(checkTypes, statusList); patientStatisticVO.setQueuingNum(num); return patientStatisticVO; } public PatientStatisticVO getBedDevInstallStatistic(Long roomId, String bedNo) { PatientStatisticVO patientStatisticVO = new PatientStatisticVO(); List bedQueueStatisticDOList = queueMapper.bedQueueStatistic(roomId, bedNo); bedQueueStatisticDOList.forEach(item -> { // } else if (QueueStatusEnum.INSTALLING.getStatus() == item.getStatus()) { // patientStatisticVO.setReceivedNum( patientStatisticVO.getReceivedNum() + item.getTotalInStatus() ); if (QueueStatusEnum.FINISH.getStatus() == item.getStatus()) { patientStatisticVO.setFinishedNum(item.getTotalInStatus()); } }); // 装机界面:统计 该诊室 [已领用] 的数量, 因为安装工位看不到 [已领用] 患者,所以无法根据装机工位来统计,只能按诊室统计 patientStatisticVO.setReceivedNum( 0 ); List roomQueueStatisticDOList = queueMapper.roomQueueStatistic(roomId); roomQueueStatisticDOList.forEach(item -> { if (QueueStatusEnum.RECEIVED.getStatus() == item.getStatus()) { patientStatisticVO.setReceivedNum( patientStatisticVO.getReceivedNum() + item.getTotalInStatus() ); } }); return patientStatisticVO; } public PatientStatisticVO getBedDevReadyStatistic(Long roomId, String bedNo) { PatientStatisticVO patientStatisticVO = new PatientStatisticVO(); List bedQueueStatisticDOList = queueMapper.bedQueueStatistic(roomId, bedNo); bedQueueStatisticDOList.forEach(item -> { if (QueueStatusEnum.READY.getStatus() == item.getStatus()) { patientStatisticVO.setReadyNum(item.getTotalInStatus()); } else if (QueueStatusEnum.PASSED.getStatus() == item.getStatus()) { patientStatisticVO.setPassedNum(item.getTotalInStatus()); } }); // 领用界面:统计 该诊室 [已领用] 的数量, 因为安装时患者归属工位从领用工位变更到安装工位,所以无法根据领用工位来统计,只能按诊室统计 patientStatisticVO.setReceivedNum( 0 ); List roomQueueStatisticDOList = queueMapper.roomQueueStatistic(roomId); roomQueueStatisticDOList.forEach(item -> { if (QueueStatusEnum.RECEIVED.getStatus() == item.getStatus()) { patientStatisticVO.setReceivedNum( patientStatisticVO.getReceivedNum() + item.getTotalInStatus() ); } else if (QueueStatusEnum.INSTALLING.getStatus() == item.getStatus()) { patientStatisticVO.setReceivedNum( patientStatisticVO.getReceivedNum() + item.getTotalInStatus() ); } else if (QueueStatusEnum.FINISH.getStatus() == item.getStatus()) { patientStatisticVO.setReceivedNum(patientStatisticVO.getReceivedNum() + item.getTotalInStatus() ); } }); // 统计 该工位类型的【排队中】人员数量 RoomDO roomDO = getRoomDO(roomId, bedNo); Integer[] checkTypes = roomDO.getCheckTypes(); List statusList = new ArrayList<>(); statusList.add(QueueStatusEnum.WAITING.getStatus()); Integer num = queueMapper.checkTypeAndStatusStatistic(checkTypes, statusList); patientStatisticVO.setQueuingNum(num); return patientStatisticVO; } public void initCheckType() { queueServiceTxFunctions.initCheckType( ); } public void startBiz() { if (1 == queueServiceTxFunctions.getOpeningFlag()) return; queueServiceTxFunctions.setOpeningFlag(1); startBedReload(); } public void closeBiz() { queueServiceTxFunctions.setOpeningFlag(0); startBedReload(); } @Override public Integer recallPatient(Long roomId, String bedNo, String patId) { Integer updateNum = queueMapper.recallPassedPatient(roomId, bedNo, patId, QueueStatusEnum.PASSED.getStatus(), QueueStatusEnum.RECALLED.getStatus()); startHurryUpOneBed(roomId, bedNo); return updateNum; } @Override public Integer recallInstallPatient(Long roomId, String bedNo, String patId) { Integer updateNum = queueMapper.recallPassedInstallPatient(roomId, bedNo, patId, QueueStatusEnum.PASSED_INSTALL.getStatus(), QueueStatusEnum.RECALLED_INSTALL.getStatus()); // 安装工位 不设计 优先队列 //startHurryUpOneBed(roomId, bedNo); return updateNum; } @Override public Integer patientJump(String patId, Byte jumped) { Integer updateNum = queueMapper.queueJump(patId, QueueStatusEnum.WAITING.getStatus(), jumped); QueueDO queueDO = queueMapper.getQueueByPatId(patId); startHurryUpOneCheckType(Integer.valueOf(queueDO.getBookCheckType())); return updateNum; } @Override public RoomDO getDocRoomInfo(Long docId) { return roomMapper.getRoomByDocId(docId); } /** * 获取 指定工位 待检查|待领用的人 * @param roomId * @param bedNo * @return */ @Override public List getToBeCheckedPatient(Long roomId, String bedNo) { List queueStatusList = new ArrayList<>(); queueStatusList.add(QueueStatusEnum.RECALLED.getStatus()); queueStatusList.add(QueueStatusEnum.READY.getStatus()); queueStatusList.add(QueueStatusEnum.ONSTAGE.getStatus()); queueStatusList.add(QueueStatusEnum.PASSED.getStatus()); List queueDOList = getBedQueueByStatus(roomId, bedNo, queueStatusList); return queueDOList; } @Override public List getToBeInstalledPatient(Long roomId, String bedNo) { List queueStatusList = new ArrayList<>(); queueStatusList.add(QueueStatusEnum.RECEIVED.getStatus()); queueStatusList.add(QueueStatusEnum.PASSED_INSTALL.getStatus()); List queueDOList = getRoomQueueByStatus(roomId, queueStatusList); queueStatusList.clear(); queueStatusList.add(QueueStatusEnum.INSTALLING.getStatus()); queueStatusList.add(QueueStatusEnum.RECALLED_INSTALL.getStatus()); queueDOList.addAll(0, getBedQueueByStatus(roomId, bedNo, queueStatusList) ); return queueDOList; } private RoomDO getRoomDO(Long roomId, String bedNo) { RoomDO roomDO = mapRoomBed.get( Utils.formatRoomBed(roomId, bedNo) ); if ( null == roomDO) roomDO = roomMapper.getRoom(roomId, bedNo); return roomDO; } }