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/controller/admin/room/RoomController.java | 287 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++
1 files changed, 287 insertions(+), 0 deletions(-)
diff --git a/jh-module-ecg/jh-module-ecg-biz/src/main/java/cn/lihu/jh/module/ecg/controller/admin/room/RoomController.java b/jh-module-ecg/jh-module-ecg-biz/src/main/java/cn/lihu/jh/module/ecg/controller/admin/room/RoomController.java
index 6f0b3de..6e5aa4b 100644
--- a/jh-module-ecg/jh-module-ecg-biz/src/main/java/cn/lihu/jh/module/ecg/controller/admin/room/RoomController.java
+++ b/jh-module-ecg/jh-module-ecg-biz/src/main/java/cn/lihu/jh/module/ecg/controller/admin/room/RoomController.java
@@ -10,6 +10,7 @@
import javax.validation.Valid;
import cn.hutool.extra.servlet.ServletUtil;
+import cn.lihu.jh.module.ecg.utils.IpUtils;
import cn.lihu.jh.module.ecg.controller.admin.room.vo.*;
import cn.lihu.jh.module.ecg.dal.dataobject.queue.QueueDO;
import cn.lihu.jh.module.ecg.dal.dataobject.room.RoomDO;
@@ -29,11 +30,16 @@
import cn.lihu.jh.framework.common.pojo.PageParam;
import cn.lihu.jh.framework.common.pojo.PageResult;
import cn.lihu.jh.framework.common.pojo.CommonResult;
+import cn.lihu.jh.framework.common.exception.ErrorCode;
+import cn.lihu.jh.framework.common.exception.enums.GlobalErrorCodeConstants;
import cn.lihu.jh.framework.common.util.object.BeanUtils;
import cn.lihu.jh.framework.excel.core.util.ExcelUtils;
import cn.lihu.jh.framework.apilog.core.annotation.ApiAccessLog;
+import cn.lihu.jh.framework.security.core.util.SecurityFrameworkUtils;
+import lombok.extern.slf4j.Slf4j;
import static cn.lihu.jh.framework.common.pojo.CommonResult.success;
+import static cn.lihu.jh.framework.common.exception.util.ServiceExceptionUtil.exception;
import static cn.lihu.jh.framework.apilog.core.enums.OperateTypeEnum.*;
@@ -41,6 +47,7 @@
@RestController
@RequestMapping("/clinic/room")
@Validated
+@Slf4j
public class RoomController {
@Resource
@@ -92,6 +99,258 @@
String reqIp = ServletUtil.getClientIP(request);
RoomProfile roomProfile = roomService.getRoomByIP(reqIp, roomId);
return success(BeanUtils.toBean(roomProfile, RoomProfileRespVO.class));
+ }
+
+ /* ==================== 閫夋嫨宸ヤ綅妯″紡锛堥渶姹傦細璇婂宸ヤ綅閫夋嫨妯″紡 0/1/2/3锛� ==================== */
+
+ /**
+ * 鎸夋湰鏈篒P鍖归厤宸ヤ綅锛堟ā寮� 1/3 鐢級銆�
+ *
+ * <p>鍙鎺ュ彛锛�
+ * <ul>
+ * <li>鎶婂悗绔疄闄呰瘑鍒埌鐨勬潵璁縄P涓�璧疯繑鍥烇紝渚夸簬鎺掓煡"鍓嶇疆浠g悊鏈�忎紶 X-Forwarded-For"锛�</li>
+ * <li>鍊欓�夊伐浣嶅凡鎸夈�屾湰浜哄凡鍗犵敤 鈫� 绌洪棽 鈫� 琚粬浜哄崰鐢ㄣ�嶆帓濂藉簭锛屽墠绔彇绗竴涓彲鐢ㄧ殑鑷姩鍏ュ骇锛�</li>
+ * <li>鏈帴鍙d笉鏀逛换浣曠姸鎬侊紝鍏ュ骇浠嶈蛋鍘熸湁鐨� bedDoctorOn 娴佺▼銆�</li>
+ * </ul>
+ * 闇�瑕佺櫥褰曪紙鏈櫥褰曟椂杩斿洖绌虹粨鏋滐級锛屼絾涓嶅仛鑿滃崟鏉冮檺鏍¢獙锛氳兘鐧诲綍灏辫兘鏌ヨ嚜宸辩殑宸ヤ綅銆�</p>
+ */
+ @GetMapping("/get-ip-bed")
+ @Operation(summary = "鎸夋湰鏈篒P鍖归厤宸ヤ綅锛堥�夋嫨宸ヤ綅妯″紡 1/3锛�")
+ public CommonResult<RoomSelectBedRespVO> getIpBed(HttpServletRequest request) {
+ // 瑙勮寖鍖栵細鍘绘嫭鍙�/鍖哄煙鍙枫�佺粺涓�灏忓啓銆両Pv4-mapped IPv6 杩樺師鎴� IPv4锛堟敮鎸� IPv4 涓� IPv6锛�
+ String clientIp = IpUtils.normalize(ServletUtil.getClientIP(request));
+ Long docId = SecurityFrameworkUtils.getLoginUserId();
+ RoomSelectBedRespVO resp = new RoomSelectBedRespVO();
+ resp.setClientIp(clientIp);
+ resp.setIpValid(IpUtils.isBindableIp(clientIp));
+ resp.setIpLoopback(IpUtils.isLoopback(clientIp));
+ resp.setIpv6(IpUtils.isIpv6Address(clientIp));
+ List<RoomSelectBedRespVO.RoomSelectBedItem> beds = roomService.matchBedsByIp(clientIp, docId);
+ resp.setBeds(beds);
+ resp.setIpBound(!beds.isEmpty());
+ // 鏈�"鏈汉宸插崰鐢�"鎴�"绌洪棽"鐨勫伐浣嶏紝灏辫兘鑷姩鍏ュ骇
+ resp.setMatched(beds.stream()
+ .anyMatch(b -> Boolean.TRUE.equals(b.getMine()) || !Boolean.TRUE.equals(b.getOccupied())));
+ log.info("[getIpBed][鎸塈P鍖归厤宸ヤ綅] clientIp={} docId={} ipValid={} loopback={} 鍊欓�夋暟={} 鍙嚜鍔ㄥ叆搴�={}",
+ clientIp, docId, resp.getIpValid(), resp.getIpLoopback(), beds.size(), resp.getMatched());
+ return success(resp);
+ }
+
+ /**
+ * 鎶婃湰鏈篒P鍐欏叆鎸囧畾宸ヤ綅锛堟ā寮� 2/3 鐢級銆�
+ *
+ * <p>鍙洿鏂� {@code clinic_room.ip} 涓�涓瓧娈碉紝涓嶈蛋 {@code clinic:room:update}锛堝惁鍒欎负浜嗛�夊伐浣嶈繕寰楃粰鍖荤敓寮�璇婂绠$悊鏉冮檺锛夛紝
+ * 涔熶笉浼氱 status/doc_id/check_types 绛夊叾瀹冨瓧娈点��
+ * 鑻ヨIP宸茬粦鍦ㄥ埆鐨勫伐浣嶄笂锛岄粯璁よ繑鍥炲啿绐佸伐浣嶈鍓嶇纭锛涚‘璁ゅ悗甯� {@code force=true} 鍐嶈皟涓�娆″嵆瑕嗙洊銆�</p>
+ */
+ @PostMapping("/bind-ip")
+ @Operation(summary = "鎶婃湰鏈篒P缁戝畾鍒板伐浣嶏紙閫夋嫨宸ヤ綅妯″紡 2/3锛�")
+ public CommonResult<Map<String, Object>> bindIp(HttpServletRequest request,
+ @RequestParam("id") Integer id,
+ @RequestParam(value = "force", required = false, defaultValue = "false") Boolean force) {
+ Map<String, Object> data = new HashMap<>();
+ String rawIp = ServletUtil.getClientIP(request);
+ String clientIp = IpUtils.normalize(rawIp);
+ data.put("clientIp", clientIp);
+ if (!IpUtils.isBindableIp(clientIp)) {
+ data.put("code", 400);
+ if (IpUtils.isLoopback(clientIp)) {
+ // 娴忚鍣ㄥ拰鏈嶅姟鍦ㄥ悓涓�鍙版満鍣ㄤ笂璁块棶鏃跺繀鐒跺嚭鐜帮細IPv4 鏄� 127.0.0.1锛孖Pv6 鏄� ::1
+ data.put("msg", "鏃犳硶缁戝畾宸ヤ綅锛氭娴嬪埌褰撳墠璁块棶鏉ヨ嚜鏈満鍥炵幆鍦板潃锛�" + clientIp
+ + "锛屽嵆鏈満璁块棶锛夛紝璇峰湪鍖荤敓瀹為檯浣跨敤鐨勭數鑴戜笂璁块棶鍚庡啀缁戝畾");
+ } else if (IpUtils.isUnspecified(clientIp)) {
+ data.put("msg", "鏃犳硶缁戝畾宸ヤ綅锛氬綋鍓嶈瘑鍒埌鐨勫湴鍧�鏄湭鎸囧畾鍦板潃锛�" + clientIp + "锛�");
+ } else if (IpUtils.isLocalAddress(clientIp)) {
+ // 鏈鏂板锛氱幇鍦烘渶甯歌鐨�"IP 涓嶅"灏辨槸杩欑 鈥斺�� 鍦ㄦ湇鍔″櫒涓婏紙鎴栬繙绋嬫闈㈤噷锛夎闂郴缁燂紝
+ // 瀹㈡埛绔湰鏉ュ氨鏄湇鍔″櫒鑷繁锛涜嫢鎶婂畠鍐欒繘宸ヤ綅锛岃宸ヤ綅浠ュ悗姘歌繙鍖归厤涓嶅埌鍖荤敓鐢佃剳銆�
+ data.put("msg", "鏃犳硶缁戝畾宸ヤ綅锛氳瘑鍒埌鐨勬槸**鏈嶅姟鍣ㄨ嚜韬湴鍧�**锛�" + clientIp
+ + "锛夆�斺�� 璇存槑褰撳墠鏄湪鏈嶅姟鍣ㄤ笂璁块棶锛屾垨缁忚繙绋嬫闈�/鏈満浠g悊璁块棶锛岃繖涓嶆槸鍖荤敓鐢佃剳鐨� IP銆�"
+ + "璇峰湪鍖荤敓瀹為檯浣跨敤鐨勭數鑴戜笂銆佺敤鏈嶅姟鍣ㄧ殑 IPv4 鍦板潃璁块棶鍚庡啀缁戝畾"
+ + "锛堝彲鐢ㄣ�孖P 璇婃柇銆嶆煡鐪嬪悗绔埌搴曟妸璋佸綋鎴愪簡瀹㈡埛绔級");
+ log.warn("[bindIp][璇嗗埆鍒版湇鍔″櫒鑷韩鍦板潃锛屾嫆缁濈粦瀹歖 clientIp={} bedId={} 鏈嶅姟鍣ㄧ綉鍗Pv4={}",
+ clientIp, id, IpUtils.localIpv4Addresses());
+ } else if (IpUtils.isIpv6Address(clientIp)) {
+ // 鏈郴缁熷伐浣嶇粦瀹氱粺涓�閲囩敤 IPv4锛涘鎴风璧� IPv6 鏃舵棤娉曚粠浠g爜"閫�鍖栨垚"IPv4
+ data.put("msg", "鏃犳硶缁戝畾宸ヤ綅锛氬綋鍓嶈闂娇鐢ㄧ殑鏄� IPv6 鍦板潃锛�" + clientIp
+ + "锛夛紝鏈郴缁熷伐浣嶇粦瀹氫粎閲囩敤 IPv4锛岃鏀圭敤鏈嶅姟鍣ㄧ殑 IPv4 鍦板潃璁块棶"
+ + "锛堟垨璁╂湇鍔″彧鐩戝惉 IPv4锛欽VM 鍙傛暟 -Djava.net.preferIPv4Stack=true锛�");
+ } else {
+ data.put("msg", "鏃犳硶缁戝畾宸ヤ綅锛氭湭鑳借瘑鍒埌鍚堟硶鐨� IPv4 鏉ヨ鍦板潃锛�" + clientIp
+ + "锛夛紝璇锋鏌ユ槸鍚﹂�氳繃浠g悊璁块棶銆佷互鍙婁唬鐞嗘槸鍚﹂�忎紶瀹㈡埛绔湴鍧�锛圶-Forwarded-For锛�");
+ }
+ log.warn("[bindIp][IP涓嶅彲鐢紝鎷掔粷缁戝畾] raw={} normalized={} ipv6={} bedId={}",
+ rawIp, clientIp, IpUtils.isIpv6Address(clientIp), id);
+ return success(data);
+ }
+ // 鍐茬獊妫�娴嬶細璇P宸茬粦鍦ㄥ埆鐨勫伐浣� 鈫� 鍏堣鍓嶇纭
+ List<RoomDO> conflicts = roomService.listIpBindings(clientIp, id);
+ if (!conflicts.isEmpty() && !Boolean.TRUE.equals(force)) {
+ RoomDO c = conflicts.get(0);
+ data.put("code", 409);
+ data.put("conflict", true);
+ data.put("conflictBedId", c.getId());
+ data.put("conflictRoomName", c.getRoomName());
+ data.put("conflictBedNo", c.getBedNo());
+ data.put("msg", "璇P宸茬粦瀹氥��" + c.getRoomName() + " / " + c.getBedNo() + "銆�");
+ return success(data);
+ }
+ Integer rows = roomService.bindIpToBed(id, clientIp);
+ data.put("code", rows != null && rows > 0 ? 200 : 500);
+ data.put("msg", rows != null && rows > 0 ? "宸茬粦瀹氭湰鏈篒P鍒拌宸ヤ綅" : "缁戝畾澶辫触锛堝伐浣嶄笉瀛樺湪锛燂級");
+ data.put("rows", rows);
+ log.info("[bindIp][缁戝畾缁撴灉] raw={} clientIp={} bedId={} force={} rows={}", rawIp, clientIp, id, force, rows);
+ return success(data);
+ }
+
+ /* ==================== 鑷姩鍏ュ骇 / 鎴戠殑宸ヤ綅锛堟湰娆¢渶姹傦級 ==================== */
+
+ /**
+ * 涓�閿嚜鍔ㄥ叆搴э紙閫夋嫨宸ヤ綅妯″紡 1/3 鐢級銆�
+ *
+ * <p>涓轰粈涔堝悎骞舵垚涓�涓帴鍙o細鍓嶇鍘熸潵鎶娿�屽尮閰� 鈫� 缁� IP 鈫� 鍏ュ骇銆嶆媶鎴愪笁涓姹傝嚜宸辨嫾锛�
+ * 浠讳竴姝ュけ璐ラ兘鍙兘鍥炶惤"鎵嬮�夊伐浣�"锛岀幇鍦鸿〃鐜板氨鏄�"鐧诲綍鍚庢病鏈夎嚜鍔ㄥ叆搴�"涓旂湅涓嶅嚭鍘熷洜銆�
+ * 鐜板湪涓�娆¤皟鐢ㄥ畬鎴愶紝骞惰繑鍥�**璇嗗埆鍒扮殑 IP** 涓�**鏈叆搴у師鍥�**
+ * 锛坽@code ip_invalid / nomatch / multi / occupied / error}锛夛紝鎺掓煡涓�鐪煎彲杈ㄣ��
+ *
+ * <p>闇�瑕佺櫥褰曪紝浣嗕笉鍋氳彍鍗曟潈闄愭牎楠岋細鑳界櫥褰曞氨鑳藉潗鑷繁鐨勫伐浣嶃��
+ */
+ @PostMapping("/auto-seat")
+ @Operation(summary = "鎸夋湰鏈篒P鑷姩鍖归厤宸ヤ綅骞惰嚜鍔ㄥ叆搴э紙閫夋嫨宸ヤ綅妯″紡 1/3锛�")
+ public CommonResult<RoomSeatRespVO> autoSeat(HttpServletRequest request) {
+ String clientIp = IpUtils.normalize(ServletUtil.getClientIP(request));
+ Long docId = SecurityFrameworkUtils.getLoginUserId();
+ String docName = SecurityFrameworkUtils.getLoginUserNickname();
+ RoomSeatRespVO resp = roomService.autoSeatByIp(clientIp, docId, docName);
+ log.info("[autoSeat][鑷姩鍏ュ骇] clientIp={} docId={} seated={} reason={} 宸ヤ綅={}/{}",
+ clientIp, docId, resp.getSeated(), resp.getReason(), resp.getRoomName(), resp.getBedNo());
+ return success(resp);
+ }
+
+ /**
+ * 鏌ヨ褰撳墠鐧诲綍浜�**宸插叆搴�**鐨勫伐浣嶏紙绯荤粺椤舵爮"褰撳墠宸ヤ綅"鏍囩鐢級銆�
+ *
+ * <p>鏈叆搴ф椂杩斿洖 {@code seated=false}锛屽墠绔嵁姝ゆ樉绀虹伆鑹层�屾湭鍏ュ骇銆嶅苟鍙偣鍑诲幓閫夊伐浣嶃��
+ */
+ @GetMapping("/my-seat")
+ @Operation(summary = "鏌ヨ褰撳墠鐧诲綍浜哄凡鍏ュ骇鐨勫伐浣嶏紙绯荤粺椤舵爮灞曠ず锛�")
+ public CommonResult<RoomSeatRespVO> mySeat() {
+ Long docId = SecurityFrameworkUtils.getLoginUserId();
+ RoomSeatRespVO resp = roomService.getMySeat(docId);
+ log.info("[mySeat][鏌ヨ鎴戠殑宸ヤ綅] docId={} seated={} 宸ヤ綅={}/{}",
+ docId, resp.getSeated(), resp.getRoomName(), resp.getBedNo());
+ return success(resp);
+ }
+
+ /**
+ * 銆愭湰闇�姹偮蜂竴浜哄宸ヤ綅銆戞煡璇㈠綋鍓嶇櫥褰曚汉鍗犳嵁鐨�**鍏ㄩ儴**宸ヤ綅锛堣妭鍋囨棩鍊肩彮澶氬矖浣嶏級銆�
+ *
+ * <p>杩斿洖銆屽尰鐢熷湪搴� / 鍖荤敓鏆傚仠銆嶇殑宸ヤ綅鍒楄〃锛屾寜 roomId + bedNo 鍗囧簭锛涙湭鍗犲伐浣嶈繑鍥炵┖鏁扮粍銆�
+ * 鍓嶇鐢ㄥ畠娓叉煋椤舵爮銆屾垜鐨勫伐浣嶏紙N 涓級銆嶅苟鍦ㄥ伐浣嶄箣闂村垏鎹€��
+ */
+ @GetMapping("/my-seats")
+ @Operation(summary = "鏌ヨ褰撳墠鐧诲綍浜哄凡鍏ュ骇鐨勫叏閮ㄥ伐浣嶏紙涓�浜哄宀椾綅锛�")
+ public CommonResult<List<RoomSeatRespVO>> mySeats() {
+ Long docId = SecurityFrameworkUtils.getLoginUserId();
+ List<RoomSeatRespVO> seats = roomService.getMySeats(docId);
+ log.info("[mySeats][鏌ヨ鎴戠殑鍏ㄩ儴宸ヤ綅] docId={} 鏁伴噺={}", docId, null == seats ? 0 : seats.size());
+ return success(seats);
+ }
+
+ /**
+ * 銆愭湰闇�姹偮锋帴鐝嚜鍔╂帴绠°�戞妸宸ヤ綅浠�"鍒汉鍗犵敤"鏀逛负"褰撳墠鐧诲綍浜哄崰鐢�"銆�
+ *
+ * <p>鍦烘櫙锛氫笂涓�鐝尰鐢熶笅鐝湭鐐广�岀搴с�嶏紝涓嬩竴鐝尰鐢熷湪鍚屼竴鍙扮數鑴�/鍚屼竴宸ヤ綅鎺ョ彮銆�
+ * 鍘熷崰鐢ㄤ汉浼氳寮哄埗绂诲骇锛堝叾椤甸潰 5s 杞浼氭彁绀恒�岃閲嶆柊灏卞潗銆嶅苟杞彧璇伙級銆�
+ * 鏉冮檺娌跨敤鍖荤敓宸ヤ綔鍙板凡鏈夌殑 {@code ecg:doctor:task}锛屾棤闇�鏂板鏉冮檺鐐广��
+ */
+ @PostMapping("/take-over-bed")
+ @Operation(summary = "鎺ョ宸ヤ綅锛堟帴鐝細鎶婁粬浜哄崰鐢ㄧ殑宸ヤ綅杞粰鎴戯級")
+ @PreAuthorize("@ss.hasPermission('ecg:doctor:task')")
+ public CommonResult<Boolean> takeOverBed(@RequestParam("roomId") Long roomId,
+ @RequestParam("bedNo") String bedNo) {
+ roomService.takeOverBed(roomId, bedNo);
+ return success(true);
+ }
+
+ /**
+ * 瀹㈡埛绔� IP 璇嗗埆璇婃柇锛堢幇鍦烘帓鏌�"宸ヤ綅缁戝畾鐨� IP 涓嶅"鐢級銆�
+ *
+ * <p>涓�娆℃妸鎵�鏈夌浉鍏崇嚎绱㈡憡寮�锛氬悇涓唬鐞嗗ご銆乀CP 鐩磋繛鍦板潃銆佽鑼冨寲缁撴灉銆佹槸鍚﹀洖鐜�/IPv6銆�
+ * **鏄惁鏄湇鍔″櫒鑷韩鍦板潃**銆佷互鍙婃湇鍔″櫒鎵�鏈� IPv4 缃戝崱鍦板潃銆傜晫闈笂鐨勩�孖P 璇婃柇銆嶆寜閽氨璋冨畠銆�
+ *
+ * <p>鍏稿瀷缁撹锛�
+ * <ul>
+ * <li>鍙栧埌鐨勬槸鏈嶅姟鍣ㄨ嚜韬湴鍧� 鈫� 褰撳墠鏄湪鏈嶅姟鍣ㄤ笂/杩滅▼妗岄潰閲岃闂紝鎴栦唬鐞嗘妸瀹㈡埛绔湴鍧�瑕嗙洊鎴愪簡鏈嶅姟鍣ㄥ湴鍧�锛�</li>
+ * <li>鍙栧埌 127.x / ::1 鈫� 娴忚鍣ㄤ笌鏈嶅姟鍦ㄥ悓涓�鍙版満鍣紱</li>
+ * <li>鍙栧埌 IPv6 鈫� 瀹㈡埛绔蛋 IPv6锛堟湰绯荤粺宸ヤ綅缁戝畾鍙敤 IPv4锛夛紱</li>
+ * <li>{@code X-Forwarded-For} 涓虹┖涓旂洿杩炲湴鍧�=缃戝叧 鈫� 鍓嶉潰鐨勪唬鐞嗘病閫忎紶瀹㈡埛绔湴鍧�銆�</li>
+ * </ul>
+ */
+ @GetMapping("/ip-debug")
+ @Operation(summary = "瀹㈡埛绔疘P璇嗗埆璇婃柇锛堟帓鏌ュ伐浣嶇粦瀹欼P涓嶅锛�")
+ public CommonResult<Map<String, Object>> ipDebug(HttpServletRequest request) {
+ Map<String, Object> data = new LinkedHashMap<>();
+ String xff = request.getHeader("X-Forwarded-For");
+ String realIp = request.getHeader("X-Real-IP");
+ String remoteAddr = request.getRemoteAddr();
+ String raw = ServletUtil.getClientIP(request);
+ String clientIp = IpUtils.normalize(raw);
+
+ data.put("璁块棶Host", request.getHeader("Host"));
+ data.put("X-Forwarded-For", xff);
+ data.put("X-Real-IP", realIp);
+ data.put("Proxy-Client-IP", request.getHeader("Proxy-Client-IP"));
+ data.put("WL-Proxy-Client-IP", request.getHeader("WL-Proxy-Client-IP"));
+ data.put("HTTP_CLIENT_IP", request.getHeader("HTTP_CLIENT_IP"));
+ data.put("鐩磋繛鍦板潃(remoteAddr)", remoteAddr);
+ data.put("鍙栧埌鐨勫師濮嬪��", raw);
+ data.put("瑙勮寖鍖栧悗(宸ヤ綅鎸夋鍖归厤)", clientIp);
+ data.put("鍙敤浜庡伐浣嶇粦瀹�", IpUtils.isBindableIp(clientIp));
+ data.put("鏄洖鐜�(娴忚鍣ㄤ笌鏈嶅姟鍚屾満)", IpUtils.isLoopback(clientIp));
+ data.put("鏄疘Pv6", IpUtils.isIpv6Address(clientIp));
+ data.put("鏄湇鍔″櫒鑷韩鍦板潃", IpUtils.isLocalAddress(clientIp));
+ data.put("鏈嶅姟鍣ㄧ綉鍗Pv4", IpUtils.localIpv4Addresses());
+
+ String verdict;
+ if (IpUtils.isLoopback(clientIp)) {
+ verdict = "瀹㈡埛绔氨鏄湇鍔″櫒鏈満锛堝洖鐜� " + clientIp + "锛夛細灞炪�愭祻瑙堝櫒涓庢湇鍔″湪鍚屼竴鍙版満鍣ㄣ�戠殑姝e父鐜拌薄锛�"
+ + "涓嶈兘浣滀负宸ヤ綅鏍囪瘑锛岃鍦ㄥ尰鐢熺數鑴戜笂璁块棶銆�";
+ } else if (IpUtils.isLocalAddress(clientIp)) {
+ verdict = "鈿� 璇嗗埆鍒扮殑鏄�愭湇鍔″櫒鑷韩鍦板潃銆戯紙" + clientIp + "锛夛細褰撳墠鏄湪鏈嶅姟鍣ㄤ笂/杩滅▼妗岄潰閲岃闂紝"
+ + "鎴栧墠缃唬鐞嗘妸瀹㈡埛绔湴鍧�瑕嗙洊鎴愪簡鏈嶅姟鍣ㄥ湴鍧� 鈫� 涓嶈兘浣滀负宸ヤ綅鏍囪瘑銆�"
+ + "璇峰湪鍖荤敓鐢佃剳涓娿�佺敤鏈嶅姟鍣ㄧ殑 IPv4 鍦板潃璁块棶锛涜嫢纭鏄湪鍖荤敓鐢佃剳涓婅闂紝璇锋鏌ヤ唬鐞嗘槸鍚﹂�忎紶 "
+ + "X-Forwarded-For锛坣ginx: proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;锛夈��";
+ } else if (IpUtils.isIpv6Address(clientIp)) {
+ verdict = "瀹㈡埛绔蛋鐨勬槸 IPv6锛�" + clientIp + "锛夛細鏈郴缁熷伐浣嶇粦瀹氬彧閲囩敤 IPv4锛�"
+ + "璇疯鏈嶅姟鍙洃鍚� IPv4锛圝VM: -Djava.net.preferIPv4Stack=true锛夋垨鏀圭敤 IPv4 鍦板潃璁块棶銆�";
+ } else if (IpUtils.isBindableIp(clientIp)) {
+ verdict = "璇嗗埆姝e父锛屽彲鐢ㄤ簬宸ヤ綅缁戝畾锛�" + clientIp;
+ } else {
+ verdict = "鏈兘璇嗗埆鍒板彲鐢ㄧ殑 IPv4 瀹㈡埛绔湴鍧�锛堝師濮嬪�硷細" + raw + "锛岀洿杩炲湴鍧�锛�" + remoteAddr
+ + "锛夛細璇锋鏌ヤ唬鐞嗘槸鍚﹂�忎紶瀹㈡埛绔湴鍧�锛圶-Forwarded-For锛夈��";
+ }
+ data.put("璇婃柇缁撹", verdict);
+
+ log.info("[ipDebug][瀹㈡埛绔疘P璇婃柇] Host={} XFF={} X-Real-IP={} remoteAddr={} 鈫� clientIp={} 鏈嶅姟鍣ㄥ湴鍧�={}",
+ request.getHeader("Host"), xff, realIp, remoteAddr, clientIp, IpUtils.isLocalAddress(clientIp));
+ return success(data);
+ }
+
+ /**
+ * 宸ヤ綅鐘舵�佽瘖鏂紙鎺掓煡"鍏ュ骇鎶ョ姸鎬佸紓甯� / 鏄庢槑绌洪棽鍗村潗涓嶄笂"锛夈��
+ *
+ * <p>鎶婂簱閲�**鍘熷琛�**鎽婂紑锛歚id / room_id / room_name / bed_no(鍚暱搴︿笌 HEX锛岀敤浜庡彂鐜扮粨灏剧┖鏍笺�佸叏瑙�) /
+ * ip / status / doc_id / doc_name / op_type / deleted / update_time`锛屽苟缁欏嚭涓�鍙ョ粨璁恒��
+ *
+ * <p>鐢ㄦ硶锛歚GET /clinic/room/bed-state?id=3` 鎴� `?roomId=118&bedNo=C1`銆�
+ */
+ @GetMapping("/bed-state")
+ @Operation(summary = "宸ヤ綅鐘舵�佽瘖鏂紙鎺掓煡鍏ュ骇鎶ョ姸鎬佸紓甯革級")
+ public CommonResult<Map<String, Object>> bedState(
+ @RequestParam(value = "id", required = false) Integer id,
+ @RequestParam(value = "roomId", required = false) Long roomId,
+ @RequestParam(value = "bedNo", required = false) String bedNo) {
+ return success(roomService.diagnoseBed(id, roomId, bedNo));
}
@GetMapping("/page")
@@ -166,6 +425,10 @@
List<RoomDO> list = roomService.simpleRoomList();
List<RoomRespVO> list2 = BeanUtils.toBean(list, RoomRespVO.class);
+ // 鏄惧紡鏍囨敞銆屾槸鍚﹀凡琚尰鐢熷崰鐢ㄣ�嶏細閫夊伐浣嶉〉鎹鏄剧ず銆屽凡鍏ュ骇锛氬紶涓夈�嶅苟**绂佺敤鍏ュ骇鎸夐挳**锛�
+ // 涓嶄緷璧� BeanUtils 鏄惁鎶� docId 澶嶅埗杩囨潵锛堝弻淇濋櫓锛涙湰娆$幇鍦哄氨鏈�"鐪嬩笉鍑烘潵璋佸崰浜嗗伐浣�"鐨勫弽棣堬級銆�
+ list2.forEach(roomRespVO -> roomRespVO.setOccupied(null != roomRespVO.getDocId()));
+
Map<Long, List<RoomRespVO>> map = list2.stream().collect(Collectors.groupingBy(RoomRespVO::getRoomId));
return success(map);
}
@@ -200,5 +463,29 @@
return success(0);
}
+ /**
+ * 銆愭湰娆¢渶姹傘�戠鐞嗗憳寮哄埗娓呯┖鏌愪釜宸ヤ綅锛堜笉瑕佹眰鏄崰鐢ㄨ�呮湰浜猴級銆�
+ * <p>
+ * 浣跨敤鍦烘櫙锛氬尰鐢熶笅鐝繕璁般�岀搴с�嶏紝鎴栨崲浜轰娇鐢ㄥ悓涓�宸ヤ綅銆�
+ * <p>
+ * 涓庡尰鐢熻嚜宸辩殑銆岀搴с�嶆帴鍙o紙{@code /ecg/doctor/bed-doctor-off}锛夌殑鍖哄埆锛�
+ * 路 璇ユ帴鍙e彧鑳芥竻**鑷繁**鍗犵敤鐨勫伐浣嶏紙SQL 甯� {@code doc_id = 褰撳墠鐢ㄦ埛}锛夛紱
+ * 路 鏈帴鍙i潰鍚戠鐞嗙锛屽彲浠ユ竻**浠讳綍浜�**鍗犵敤鐨勫伐浣嶏紙浠呰姹傝宸ヤ綅褰撳墠鏄�屽尰鐢熷湪宀� / 鏆傚仠銆嶏級銆�
+ * <p>
+ * 宸ヤ綅绌洪棽鏃朵細杩斿洖銆屽綋鍓嶅伐浣嶇姸鎬佷笉鍏佽璇ユ搷浣溿�嶁�斺�旇繖鏄鏈熻涓恒��
+ */
+ @PostMapping("/force-clear-bed")
+ @Operation(summary = "绠$悊鍛樺己鍒舵竻绌哄伐浣�", description = "鍖荤敓涓嬬彮蹇樼搴� / 鎹汉浣跨敤鍚屼竴宸ヤ綅鏃朵娇鐢�")
+ @PreAuthorize("@ss.hasPermission('clinic:room:update')")
+ public CommonResult<Boolean> forceClearBed(@RequestParam("roomId") Long roomId,
+ @RequestParam("bedNo") String bedNo) {
+ ErrorCode ec = queueService.startBedDoctorOffByAdmin(roomId, bedNo);
+ if (!GlobalErrorCodeConstants.SUCCESS.getCode().equals(ec.getCode())) {
+ log.warn("[forceClearBed] 娓呯┖宸ヤ綅澶辫触 roomId={} bedNo={} code={} msg={}",
+ roomId, bedNo, ec.getCode(), ec.getMsg());
+ throw exception(ec);
+ }
+ return success(true);
+ }
}
--
Gitblit v1.9.3