From 68ff33beff11310e830b0615b5a81f83fad0f683 Mon Sep 17 00:00:00 2001
From: yxh <172933527@qq.com>
Date: 星期日, 08 十一月 2026 23:33:14 +0800
Subject: [PATCH] ai优化
---
jh-module-ecg/jh-module-ecg-biz/src/main/java/cn/lihu/jh/module/ecg/service/queue/QueueServiceImpl.java | 176 +++++++++++++++++++++++++++++++++++++++++++++++++---------
1 files changed, 148 insertions(+), 28 deletions(-)
diff --git a/jh-module-ecg/jh-module-ecg-biz/src/main/java/cn/lihu/jh/module/ecg/service/queue/QueueServiceImpl.java b/jh-module-ecg/jh-module-ecg-biz/src/main/java/cn/lihu/jh/module/ecg/service/queue/QueueServiceImpl.java
index 4b6f9e4..6c3f1e9 100644
--- a/jh-module-ecg/jh-module-ecg-biz/src/main/java/cn/lihu/jh/module/ecg/service/queue/QueueServiceImpl.java
+++ b/jh-module-ecg/jh-module-ecg-biz/src/main/java/cn/lihu/jh/module/ecg/service/queue/QueueServiceImpl.java
@@ -2,6 +2,7 @@
import java.util.*;
import java.util.concurrent.*;
+import java.util.stream.Collectors;
import javax.annotation.Resource;
import cn.lihu.jh.module.ecg.Utils;
@@ -192,9 +193,41 @@
return ECG_INNER_ERROR;
}
+ /**
+ * 銆屾湰璇婂鎺掗槦涓紙鏈垎閰嶅伐浣嶏級銆嶇殑鎮h�呭垪琛ㄣ��
+ *
+ * <p>宸ヤ綔鍙板�欒瘖鍒楄〃鎸� {@code room_id + bed_no} 鏌ワ紝鍙湅寰楀埌**宸插垎娴佸埌鏈伐浣�**鐨勬偅鑰咃紱
+ * 鑰�"鎺掗槦涓�(10)"鐨勬偅鑰� {@code bed_no} 涓虹┖锛堝ぇ灞忎細鏄剧ず銆佸伐浣滃彴鐪嬩笉鍒帮級锛�
+ * 杩欓噷鎸�**鏈伐浣嶅紑灞曠殑妫�鏌ラ」鐩�**鎶婁粬浠崟鐙煡鍑烘潵锛屼緵鍖荤敓鎵嬪伐鎷夊叆銆�
+ *
+ * <p>宸ヤ綅涓嶅瓨鍦ㄦ垨娌¢厤妫�鏌ラ」鐩椂杩斿洖绌哄垪琛紙璁拌鍛婏級锛屼笉鎶涘紓甯� 鈥斺�� 鍒楄〃涓虹┖涓嶅奖鍝嶄富娴佺▼銆�
+ */
@Override
- public ErrorCode startBedDoctorOn(Long roomId, String bedNo, Long docId, String docName) {
- Future<ErrorCode> future = singleThreadExecutor.submit(new BedDoctorOnCallable(queueServiceTxFunctions, roomId, bedNo, docId, docName));
+ public List<QueueDO> getUnassignedWaitingPatient(Long roomId, String bedNo) {
+ RoomDO bed = (null == roomId || null == bedNo) ? null : roomMapper.getRoom(roomId, bedNo);
+ if (null == bed || null == bed.getCheckTypes() || 0 == bed.getCheckTypes().length) {
+ log.warn("[getUnassignedWaitingPatient] 宸ヤ綅涓嶅瓨鍦ㄦ垨鏈厤缃鏌ラ」鐩紝杩斿洖绌�. roomId={} bedNo={}",
+ roomId, bedNo);
+ return new ArrayList<>();
+ }
+ return queueMapper.selectUnassignedWaitingByCheckTypes(
+ QueueStatusEnum.WAITING.getStatus(), bed.getCheckTypes());
+ }
+
+ /**
+ * 鎵嬪伐鎶婃煇浣嶃�屾帓闃熶腑銆嶆偅鑰呮媺鍏ユ湰宸ヤ綅锛堚啋 鍑嗗涓級銆�
+ *
+ * <p>鏉冮檺鐢� Controller 涓婄殑 {@code @RequireBedOwner} 淇濊瘉锛氬彧鏈夋湰宸ヤ綅涓讳汉鑳芥媺銆�
+ * 杩欓噷鍙仛涓氬姟鏍¢獙涓庢潯浠舵洿鏂帮紙骞跺彂瀹夊叏锛歿@code and status = 10}锛夛紝骞跺鐢ㄨ嚜鍔ㄥ垎娴佺殑浜插拰椤归�昏緫銆�
+ */
+ @Override
+ public ErrorCode pullWaitingPatient(Long roomId, String bedNo, Integer queueId) {
+ return queueServiceTxFunctions.pullWaitingPatient(roomId, bedNo, queueId);
+ }
+
+ @Override
+ public ErrorCode startBedDoctorOn(Long roomId, String bedNo, Long docId, String docName, Integer bedId) {
+ Future<ErrorCode> future = singleThreadExecutor.submit(new BedDoctorOnCallable(queueServiceTxFunctions, roomId, bedNo, docId, docName, bedId));
try {
ErrorCode ret = future.get();
@@ -223,6 +256,27 @@
}
//System.out.println("startBedDoctorOff ========");
+ return ECG_INNER_ERROR;
+ }
+
+ /**
+ * 銆愭湰娆¢渶姹傘�戠鐞嗗憳寮哄埗娓呯┖宸ヤ綅锛堜笉瑕佹眰鏄湰浜猴級銆�
+ * <p>
+ * 涓� {@link #startBedDoctorOff} 鍏辩敤鍚屼竴涓崟绾跨▼鎵ц鍣紝淇濊瘉鍚屼竴鏃跺埢鍙鐞嗕竴涓伐浣嶆搷浣滐紝
+ * 閬垮厤涓庛�屽彨鍙� / 鍏ュ骇 / 绂诲骇銆嶅苟鍙戞敼鍚屼竴琛屻��
+ */
+ @Override
+ public ErrorCode startBedDoctorOffByAdmin(Long roomId, String bedNo) {
+ Future<ErrorCode> future = singleThreadExecutor.submit(
+ () -> queueServiceTxFunctions.bedDoctorOffByAdmin(roomId, bedNo));
+ try {
+ return future.get();
+ } catch (InterruptedException e) {
+ Thread.currentThread().interrupt();
+ log.error("[绠$悊鍛樻竻绌哄伐浣峕 琚腑鏂�", e);
+ } catch (ExecutionException e) {
+ log.error("[绠$悊鍛樻竻绌哄伐浣峕 鎵ц澶辫触", e.getCause() != null ? e.getCause() : e);
+ }
return ECG_INNER_ERROR;
}
@@ -265,6 +319,12 @@
singleThreadExecutor.execute(() -> {
queueServiceTxFunctions.hurryupOneBed(roomId, bedNo);
});
+ }
+
+ @Override
+ public Map<String, Object> hurryUpNow(Long roomId, String bedNo) {
+ // 鍚屾鎵ц锛氳绔嬪埢杩斿洖"琛ヤ汉鍓嶅悗浜烘暟 + 缁撹"锛屽紓姝ュ氨鐪嬩笉鍒扮粨鏋滀簡
+ return queueServiceTxFunctions.hurryUpNow(roomId, bedNo);
}
@Override
@@ -365,8 +425,8 @@
}
@Override
- public List<QueueDO> selectBookSeqNumByAppointIdList(List<Long> appointIdList) {
- return queueMapper.selectBookSeqNumByAppointIdList(appointIdList);
+ public List<QueueDO> selectQueueByAppointIdList(List<Long> appointIdList) {
+ return queueMapper.selectQueueByAppointIdList(appointIdList);
}
// 甯歌妫�鏌� 鍙彿
@@ -427,7 +487,11 @@
// 浠� DB 鎶� [瀹夎涓璢鐨勪汉 璁剧疆涓� [杩囧彿-瀹夎]
Integer ret = queueMapper.updateBedQueueStatus(roomId, bedNo, QueueStatusEnum.INSTALLING.getStatus(), QueueStatusEnum.PASSED_INSTALL.getStatus());
- startNextPatient(roomId, bedNo);
+ // 銆愭棦鏈夌瑪璇慨澶嶃�戣繖閲屽師鏈皟鐨勬槸 startNextPatient锛堝父瑙勬鏌ュ彇浜猴細鍊欒瘖涓� 鈫� 灏辫瘖涓級锛�
+ // 鑰岃鏈鸿繃鍙峰悗搴斿綋缁х画鍙�**瀹夎闃熷垪**閲岀殑涓嬩竴浣嶏紙宸查鐢�/宸插彫鍥�-瀹夎 鈫� 瀹夎涓級銆�
+ // 鐢变簬瑁呮満宸ヤ綅涓嶅弬涓庡垎娴併�佹病鏈�"鍊欒瘖涓�"鎮h�咃紝鍘熻皟鐢ㄥ疄闄呬笂浠�涔堜篃涓嶄細鍙戠敓锛�
+ // 琛ㄧ幇涓�"瑁呮満杩囧彿鍚庝笉浼氳嚜鍔ㄥ彨涓嬩竴浣�"銆�
+ startNextInstallPatient(roomId, bedNo);
}
public List<QueueDO> getBedQueueByStatus(Long roomId, String bedNo, List<Integer> statusList) {
@@ -439,19 +503,57 @@
/**
* 浠庨绾﹀崟琛ラ綈 queue 琛ㄤ笂娌℃湁鐨勬偅鑰呬俊鎭��
*
- * queue 琛ㄤ笉瀛樿繖浜涘瓧娈碉紝浣嗗尰鐢熺鍒楄〃鎺ュ彛闇�瑕佸睍绀猴紝鎵�浠ユ煡璇㈠悗鎸� applyNo 鍥炴煡棰勭害鍗曞~鍏咃細
- * 澶氳�愯嵂銆佹�у埆銆佸嚭鐢熸棩鏈熴�佺櫥璁版椂闂淬�佸紑鍗曞尰甯堛�佸紑鍗曟棩鏈熴��
+ * <p>queue 琛ㄤ笉瀛樿繖浜涘瓧娈碉紝浣嗗尰鐢熺鍒楄〃鎺ュ彛闇�瑕佸睍绀猴紝鎵�浠ユ煡璇㈠悗鎸� applyNo 鍥炴煡棰勭害鍗曞~鍏咃細
+ * 澶氳�愯嵂銆佹�у埆銆佸嚭鐢熸棩鏈熴�佺櫥璁版椂闂淬�佸紑鍗曞尰甯堛�佸紑鍗曟棩鏈熴��</p>
+ *
+ * <h3>鈿狅笍 鎬ц兘淇锛氱敱 N+1 鏀逛负涓�娆℃壒閲忔煡璇�</h3>
+ * <p><b>鍘熷疄鐜�</b>鍦� {@code forEach} 閲屽姣忎竴琛岃皟鐢�
+ * {@code appointmentMapper.getByApplyNo(applyNo)}锛屽嵆**姣忚涓�娆� SQL**銆�
+ * 鍒楄〃姣忛〉 10 鏉� 鈬� 10 娆℃煡璇紱鑰岃 SQL
+ * 锛坽@code WHERE apply_no = ? AND deleted = 0}锛夊湪淇鍓�**鐢ㄤ笉涓婄储寮�**锛�
+ * 姣忔閮芥槸鍏ㄨ〃鎵弿 appointment锛堝疄娴� 16.6 涓囪锛岀害 549 ms/娆★級锛�
+ * 涓�椤靛氨瑕� 4.5~5.5 绉� 鈥斺�� 杩欐槸銆岄槦鍒楀垪琛ㄦ墦寮�寰堟參銆嶇殑鐩存帴鍘熷洜銆�</p>
+ *
+ * <p><b>鐜板疄鐜�</b>鏀逛负锛氬厛鏀堕泦鏈〉鎵�鏈� applyNo锛堝幓閲嶏級鈫� **涓�娆�**
+ * {@code getByApplyNoList} 鎵归噺鍙栧洖 鈫� 鍐呭瓨閲屾寜 applyNo 寤烘槧灏勫啀鍥炲~銆�
+ * 涓�椤� SQL 浠� 10 娆¢檷鍒� 1 娆°��</p>
+ *
+ * <p>娉細閰嶅宸蹭簬 {@code 26_add_index_appointment_apply_no.sql}
+ * 缁� {@code appointment.apply_no} 鍔犱笂绱㈠紩锛�
+ * 浣嗗嵆渚挎湁绱㈠紩锛孨+1 浠嶆槸 10 娆″線杩旓紝鏁呬袱澶勪竴璧锋敼鎵嶆槸鏈�浼樸��</p>
*/
@Override
public void fillAppointmentInfo(List<QueueDO> queueDOList) {
if (CollectionUtils.isEmpty(queueDOList)) {
return;
}
+ // 1. 鏀堕泦鏈闇�瑕佸洖鏌ョ殑鐢宠鍗曞彿锛堣烦杩囩┖鍊硷級銆�
+ // 鐢� LinkedHashSet 鍘婚噸锛氬悓涓�椤甸噷鐞嗚涓� apply_no 鍞竴锛屼絾鍘婚噸鍚� IN 鍒楄〃鏇寸煭銆佹洿瀹夊叏銆�
+ Set<String> applyNoSet = new LinkedHashSet<>();
+ for (QueueDO queueDO : queueDOList) {
+ if (queueDO != null && queueDO.getApplyNo() != null && !queueDO.getApplyNo().isEmpty()) {
+ applyNoSet.add(queueDO.getApplyNo());
+ }
+ }
+ if (applyNoSet.isEmpty()) {
+ return;
+ }
+
+ // 2. 涓�娆℃壒閲忓彇鍥烇紙SQL 鍐呴儴宸插甫 deleted = 0锛夈��
+ // 娉ㄦ剰锛歁ySQL 鐨� IN () 浼氳娉曢敊璇紝鏁呭繀椤讳繚璇佸垪琛ㄩ潪绌� 鈥斺�� 涓婇潰宸插垽绌恒��
+ List<AppointmentDO> appointmentList = appointmentMapper.getByApplyNoList(new ArrayList<>(applyNoSet));
+
+ // 3. 鎸� applyNo 寤烘槧灏勶紱涓埆 applyNo 鏌ヤ笉鍒伴绾﹀崟鏄甯告儏鍐碉紙鍘嗗彶鑴忔暟鎹級锛岃烦杩囧嵆鍙��
+ Map<String, AppointmentDO> appointmentMap = appointmentList.stream()
+ .filter(item -> item != null && item.getApplyNo() != null)
+ .collect(Collectors.toMap(AppointmentDO::getApplyNo, item -> item, (a, b) -> a));
+
+ // 4. 鍐呭瓨鍥炲~锛屼笉鍐嶉�愭潯鏌ュ簱
queueDOList.forEach(queueDO -> {
- if (null == queueDO.getApplyNo() || queueDO.getApplyNo().isEmpty()) {
+ if (queueDO == null || queueDO.getApplyNo() == null || queueDO.getApplyNo().isEmpty()) {
return;
}
- AppointmentDO appointment = appointmentMapper.getByApplyNo(queueDO.getApplyNo());
+ AppointmentDO appointment = appointmentMap.get(queueDO.getApplyNo());
if (null == appointment) {
return;
}
@@ -624,6 +726,19 @@
public void closeBiz() {
queueServiceTxFunctions.setOpeningFlag(0);
+
+ // 銆愭湰娆¢渶姹傘�戦棴璇婃椂娓呯┖褰撶彮宸ヤ綅锛坉oc_id / doc_name 缃┖锛岀姸鎬佹敼鍥炵┖闂诧級銆�
+ //
+ // 鑳屾櫙锛氬伐浣嶄笉鍐嶅洜銆岀┖闂茶秴鏃� / 浠ょ墝澶辨晥 / 鍒锋柊椤甸潰銆嶈閲婃斁锛堥伩鍏嶅尰鐢熺寮�涓�浼氬効灏变涪宸ヤ綅锛夛紝
+ // 鍥犳闇�瑕佷竴涓厹搴� 鈥斺�� 姣忓ぉ闂瘖鏃剁粺涓�娓呯┖锛岄槻姝㈠尰鐢熶笅鐝繕绂诲骇瀵艰嚧宸ヤ綅闀挎湡琚崰鐢ㄣ��
+ // 鍏堟竻搴擄紝鍐嶇敱涓嬮潰鐨� startBedReload() 鎸夊簱閲嶆柊瑁呰浇鍐呭瓨锛屼繚璇佷簩鑰呬竴鑷淬��
+ try {
+ queueServiceTxFunctions.closeBizClearBeds();
+ } catch (Exception e) {
+ // 娓呯┖澶辫触涓嶈兘闃绘柇闂瘖娴佺▼鏈韩
+ log.error("[闂瘖] 娓呯┖褰撶彮宸ヤ綅澶辫触锛堜笉褰卞搷闂瘖锛�", e);
+ }
+
startBedReload();
}
@@ -635,6 +750,25 @@
// 浼氬湪 HurryUpOnBed 閲岄潰澶勭悊 妫�鏌ラ」鐩�.浜插拰鎬�
startHurryUpOneBed(roomId, bedNo);
+
+ // 銆愯瘖鏂�戣ˉ浜哄惊鐜湁涓夐亾闂ㄩ椄锛堟湭寮�璇� / 宸插仠姝㈠�欒瘖 / 鍊欒瘖鍖哄凡婊★級锛�
+ // 浠讳竴鏉℃垚绔嬫椂鎮h�呬細**鍋滃湪銆屽凡鍙洖(15)銆嶄笉杩涘�欒瘖鍖�**銆�
+ // 鐜板湪 nextPatient 鏀寔鐩存帴浠庛�屽凡鍙洖銆嶅彨鍙凤紙2026-10-29 淇锛夛紝杩欓噷鍙ˉ涓�鏉℃棩蹇楁柟渚跨幇鍦烘帓鏌ャ��
+ if (null != updateNum && updateNum > 0) {
+ try {
+ QueueDO stillRecalled = queueMapper.getBedQueueItemByPatAndStatus(
+ roomId, bedNo, patId, checkType, QueueStatusEnum.RECALLED.getStatus());
+ if (null != stillRecalled) {
+ log.warn("[recallPatient] 宸茬疆涓恒�屽凡鍙洖銆嶏紝浣嗘湭杩涘叆鍊欒瘖鍖�"
+ + "锛堝彲鑳藉師鍥狅細鏈紑璇� / 宸插仠姝㈠�欒瘖 / 鍊欒瘖鍖哄凡婊★級锛屽彨鍙锋椂灏嗙洿鎺ヤ粠銆屽凡鍙洖銆嶅彇浜�. "
+ + "宸ヤ綅={}/{} patId={} seqNum={}",
+ roomId, bedNo, patId, stillRecalled.getSeqNum());
+ }
+ } catch (Exception e) {
+ log.warn("[recallPatient] 妫�鏌ャ�屽凡鍙洖銆嶆槸鍚﹁繘鍏ュ�欒瘖鍖烘椂寮傚父锛堜笉褰卞搷鍙洖缁撴灉锛�. 宸ヤ綅={}/{} patId={}",
+ roomId, bedNo, patId, e);
+ }
+ }
return updateNum;
}
@@ -764,7 +898,7 @@
queueStatusList.add(QueueStatusEnum.AFFINITY.getStatus());
List<QueueDO> queueDOList = getBedQueueByStatus(roomId, bedNo, queueStatusList);
- //鎶� [浜插拰鐨刔 鎸埌涓婚」鍚庨潰
+ //鎶� [浜插拰鐨刔 鎸埌涓婚」鍚庨潰锛堝悓鎺掗槦鍙� + 鍚屾偅鑰呮墠绠椾竴缁勶紝瑙� Utils#insertAffinityItemsAfterMain锛�
List<QueueDO> affinityWaitingList = new ArrayList<>();
ListIterator<QueueDO> iterator = queueDOList.listIterator();
while (iterator.hasNext()) {
@@ -774,14 +908,7 @@
affinityWaitingList.add(item);
}
}
- affinityWaitingList.forEach(affinityWaitingItem -> {
- for (int i = queueDOList.size() - 1; i >= 0; i--) {
- if (affinityWaitingItem.getSeqNum() == queueDOList.get(i).getSeqNum()) {
- queueDOList.add(i + 1, affinityWaitingItem);
- break;
- }
- }
- });
+ Utils.insertAffinityItemsAfterMain(queueDOList, affinityWaitingList);
return queueDOList;
}
@@ -811,7 +938,7 @@
//
// 鑳屾櫙锛氫笂闈袱澶勬煡璇㈢殑鏉′欢鏄� `room_id = ? AND status IN (...)`
// 锛坓etRoomQueueByStatus 鐢氳嚦**涓嶅惈 bed_no**锛夛紝**瀹屽叏涓嶇湅 book_check_type**銆�
- // 鑰岃嚜鍔ㄥ垎娴侊紙preemptWaitingPatientWithBedCheckTypes锛夋槸**鎸夊伐浣� checkTypes 杩囨护**鐨勶紝
+ // 鑰岃嚜鍔ㄥ垎娴侊紙QueueMapper#getFirstWaitingByCheckTypes + preemptWaitingPatientById锛夋槸**鎸夊伐浣� checkTypes 杩囨护**鐨勶紝
// 鎵�浠ュ彧鏈�"浜哄伐鎶婃偅鑰呮媺杩涙潵"杩欐潯璺緞浼氭紡 鈥斺�� 琛ㄧ幇涓�
// 銆岃澶囬鐢ㄣ�嶉〉閿欒鍑虹幇甯歌蹇冪數鍥�(100)銆佸钩鏉胯繍鍔ㄥ績鐢�(400)绛�**涓嶉渶棰嗙敤璁惧**鐨勬偅鑰呫��
//
@@ -828,7 +955,7 @@
// 鏁呰繖閲屽彟璧蜂竴涓� final 鍙橀噺锛岃�屼笉鏄鐢ㄤ笂闈㈢殑 queueDOList锛堝畠宸茶閲嶆柊璧嬪�硷級銆�
final List<QueueDO> installQueueList = queueDOList;
- //鎶� [浜插拰鐨刔 鎸埌涓婚」鍚庨潰
+ //鎶� [浜插拰鐨刔 鎸埌涓婚」鍚庨潰锛堝悓鎺掗槦鍙� + 鍚屾偅鑰呮墠绠椾竴缁勶紝瑙� Utils#insertAffinityItemsAfterMain锛�
List<QueueDO> affinityReceivedList = new ArrayList<>();
ListIterator<QueueDO> iterator = installQueueList.listIterator();
while (iterator.hasNext()) {
@@ -838,14 +965,7 @@
affinityReceivedList.add(item);
}
}
- affinityReceivedList.forEach(affinityReceivedItem -> {
- for (int i = installQueueList.size() - 1; i >= 0; i--) {
- if (affinityReceivedItem.getSeqNum() == installQueueList.get(i).getSeqNum()) {
- installQueueList.add(i + 1, affinityReceivedItem);
- break;
- }
- }
- });
+ Utils.insertAffinityItemsAfterMain(installQueueList, affinityReceivedList);
return installQueueList;
}
--
Gitblit v1.9.3