eight
2024-08-22 a7b5ec90a38f93bc1da2f48676c16bb757cb05f7
jh-module-ecg/jh-module-ecg-biz/src/main/java/cn/lihu/jh/module/ecg/service/queue/queueServiceImpl.java
@@ -1,5 +1,6 @@
package cn.lihu.jh.module.ecg.service.queue;
import cn.lihu.jh.module.ecg.dal.dataobject.queue.BedQueueStatisticDO;
import cn.lihu.jh.module.ecg.dal.dataobject.queue.QueueStatisticDO;
import cn.lihu.jh.module.ecg.dal.dataobject.room.RoomDO;
import cn.lihu.jh.module.ecg.dal.mysql.room.RoomMapper;
@@ -17,10 +18,8 @@
import javax.annotation.Resource;
import java.util.*;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.PriorityBlockingQueue;
import java.util.concurrent.*;
import java.util.concurrent.atomic.AtomicInteger;
import java.util.concurrent.atomic.AtomicReference;
import static cn.lihu.jh.framework.common.exception.util.ServiceExceptionUtil.exception;
import static cn.lihu.jh.module.ecg.enums.ErrorCodeConstants.*;
@@ -34,12 +33,14 @@
@Validated
public class QueueServiceImpl implements QueueService {
    final static Integer MAX_QUEUE_NUM = 2;
    final static Integer MAX_QUEUE_NUM = 3;
    AtomicInteger curSeqNum = new AtomicInteger(0);
    PriorityBlockingQueue<BedQueueBO> priorityQueue = new PriorityBlockingQueue<>();
    ConcurrentHashMap<String, BedQueueBO > mapBedVsQueue = new ConcurrentHashMap<>();
    ExecutorService singleThreadExecutor = Executors.newSingleThreadExecutor();
    @Resource
    private queueMapper queueMapper;
@@ -89,11 +90,9 @@
        return queueMapper.selectPage(pageReqVO);
    }
    @Override
    public List<QueueStatisticDO> queueStatistics(List<Byte> statusList) {
        return queueMapper.queueStatistic(statusList);
    }
    /**
     * 系统重启时,从DB同步队列数据到 工位优先队列
     */
    public void initQueue() {
        priorityQueue.clear();
        mapBedVsQueue.clear();
@@ -110,17 +109,22 @@
        bedQueueBOList.forEach(item -> {
            item.maxQueueNum = MAX_QUEUE_NUM;
            Optional<QueueStatisticDO> queueStatisticDOOptional = queueStatisticDOList.stream().filter(it->it.getRoomId()==item.roomId && it.getBedNo().equals(item.getBedNo())).findFirst();
            item.queueNum.set( queueStatisticDOOptional.isPresent() ? queueStatisticDOOptional.get().getTotalInStatus() : 0 );
            int queueNum = queueStatisticDOOptional.isPresent() ? queueStatisticDOOptional.get().getTotalInStatus() : 0;
            if ( MAX_QUEUE_NUM < queueNum )
                throw new RuntimeException("init: exceed max queue number!");
            item.queueNum.set( queueNum );
            priorityQueue.offer(item);
            mapBedVsQueue.put(String.format("%09d%s", item.roomId, item.bedNo), item);
        });
        Integer num = queueMapper.getMaxSeqNum();
        curSeqNum = new AtomicInteger(null == num ? 1 : ++num);
        hurryup();
        curSeqNum = new AtomicInteger(null == num ? 0 : num);
    }
    /**
     * 这个逻辑 不需要了
     */
    public void reorderQueue() {
        // 根据预约前后,从DB 获取 队列中 就诊准备中人员 列表
        List<Byte> queueStatusList = new ArrayList<>();
@@ -146,55 +150,77 @@
            if (null == bedQueueBO)
                return;
            if (bedQueueBO.queueNum.get() == bedQueueBO.maxQueueNum)
            int curQueueNum = bedQueueBO.queueNum.get();
            if (curQueueNum > bedQueueBO.maxQueueNum)
                throw new RuntimeException("hurryup: exceed max queue number!");
            if (curQueueNum == bedQueueBO.maxQueueNum)
                return;
            QueueDO  queue = queueMapper.getFirstInQueueByStatus(QueueStatusEnum.WAITING.getStatus());
            if (null == queue)
                return;
            Integer updateNum = queueMapper.preemptPatient(
                    bedQueueBO.getRoomId(),
                    bedQueueBO.getRoomName(),
                    bedQueueBO.getBedNo(),
                    curSeqNum.get() + 1,
                    QueueStatusEnum.WAITING.getStatus(),
                    QueueStatusEnum.READY.getStatus());
            queue.setStatus(QueueStatusEnum.READY.getStatus()); //候诊准备中
            queue.setRoomId(bedQueueBO.getRoomId());
            queue.setRoomName(bedQueueBO.getRoomName());
            queue.setBedNo(bedQueueBO.getBedNo());
            queue.setSeqNum(curSeqNum.get());
            queueMapper.updateById(queue);  // queue.getId();
            // 没有抢到排队患者
            if (null == updateNum || 0 == updateNum) {
                return;
            }
            curSeqNum.getAndIncrement();
            bedQueueBO.queueNum.getAndIncrement();
            BedQueueBO bedQueueBO2 = priorityQueue.poll();
            priorityQueue.offer(bedQueueBO2);
            // 可能已经【并发的】在 nextPatient 中改变了值
            bedQueueBO.queueNum.incrementAndGet();
            // 可能已经【并发的】在 nextPatient 中改变了优先队列顺序
            priorityQueue.remove(bedQueueBO);
            priorityQueue.offer(bedQueueBO);
        }
    }
    /**
     * 预约确认后的排队
     * @param queueSaveReqVO
     */
    @Override
    public void queue(QueueSaveReqVO queueSaveReqVO) {
        queueSaveReqVO.setStatus(QueueStatusEnum.WAITING.getStatus()); //排队中
        QueueDO queue = BeanUtils.toBean(queueSaveReqVO, QueueDO.class);
        queueMapper.insert(queue);  // queue.getId();
        queueMapper.insert(queue);
        hurryup();
        singleThreadExecutor.execute( () -> {
            hurryup();
        });
    }
    private void nextPatient(Long roomId, String bedNo) {
        // 从 DB 把 序号最小的 就诊准备中的人 设置为就诊中
        queueMapper.updateQueueStatus(roomId, bedNo,
        Integer updateNum = queueMapper.updateQueueStatus(roomId, bedNo,
                QueueStatusEnum.READY.getStatus(), QueueStatusEnum.ONSTAGE.getStatus());
        // 该工位 没有 就诊准备中 人员
        if (null == updateNum || 0 == updateNum) {
            return;
        }
        // 优先队列中 该工位 就诊准备中人的数量 减一
        BedQueueBO bo = mapBedVsQueue.get(String.format("%09d%s", roomId, bedNo));
        boolean breturn = priorityQueue.remove(bo);
        bo.queueNum.getAndDecrement();
        bo.queueNum.getAndDecrement(); // 可能已经【并发的】在 hurry-up 中改变了值
        priorityQueue.remove(bo);
        priorityQueue.offer(bo);
        hurryup();
        singleThreadExecutor.execute( () -> {
            hurryup();
        });
    }
    public void finishNextPatient(Long roomId, String bedNo) {
        // 从 DB 把 就诊中的人 设置为就诊完成
        Integer ret =  queueMapper.updateQueueStatus(roomId, bedNo,
                QueueStatusEnum.ONSTAGE.getStatus(), QueueStatusEnum.FINISH.getStatus());
        System.out.println("完成数量: " + ret);
        nextPatient(roomId, bedNo);
    }
@@ -203,7 +229,6 @@
        // 从 DB 把 就诊中的人 设置为过号
        Integer ret =  queueMapper.updateQueueStatus(roomId, bedNo,
                QueueStatusEnum.ONSTAGE.getStatus(), QueueStatusEnum.PASSED.getStatus());
        System.out.println("完成数量: " + ret);
        nextPatient(roomId, bedNo);
    }
@@ -213,4 +238,25 @@
        return queueDOList;
    }
    public PatientStatisticVO getPatientStatistic(Long roomId, String bedNo) {
        PatientStatisticVO patientStatisticVO = new PatientStatisticVO();
        List<BedQueueStatisticDO> 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());
            }
        });
        List<Byte> statusList = new ArrayList<>();
        statusList.add(QueueStatusEnum.WAITING.getStatus());
        Integer num = queueMapper.statusStatistic(statusList);
        patientStatisticVO.setQueuingNum(num);
        return patientStatisticVO;
    }
}