ソースを参照

看板和电子病历查询

xiaochan 8 ヶ月 前
コミット
e99207cc68
18 ファイル変更194 行追加76 行削除
  1. 3 3
      pom.xml
  2. 0 5
      thyy-emr-query/src/main/java/org/thyy/emrquery/controller/emr/EmrQualityControlController.java
  3. 0 1
      thyy-emr-query/src/main/java/org/thyy/emrquery/controller/timeLimitPrompt/TimeLimitPromptController.java
  4. 5 5
      thyy-emr-query/src/main/java/org/thyy/emrquery/dao/EmrQualityControlDao.java
  5. 1 8
      thyy-emr-query/src/main/java/org/thyy/emrquery/dao/timeLimitPrompt/TimeLimitPromptDao.java
  6. 0 1
      thyy-emr-query/src/main/java/org/thyy/emrquery/entity/emr/PatientInfo.java
  7. 45 10
      thyy-emr-query/src/main/java/org/thyy/emrquery/service/emr/EmrQualityControlService.java
  8. 0 1
      thyy-emr-query/src/main/java/org/thyy/emrquery/service/emr/electronicMedicalRecords/FragmentInterval.java
  9. 0 1
      thyy-emr-query/src/main/java/org/thyy/emrquery/service/timeLimitPrompt/TimeLimitPromptService.java
  10. 1 1
      thyy-haikang/pom.xml
  11. 7 4
      thyy-haikang/src/main/java/org/thyy/haikang/controller/DoorController.java
  12. 4 3
      thyy-haikang/src/main/java/org/thyy/haikang/controller/OrgController.java
  13. 10 3
      thyy-haikang/src/main/java/org/thyy/haikang/dao/DoorDao.java
  14. 3 3
      thyy-haikang/src/main/java/org/thyy/haikang/dao/OrgDao.java
  15. 15 25
      thyy-haikang/src/main/java/org/thyy/haikang/service/DoorService.java
  16. 9 2
      thyy-haikang/src/main/java/org/thyy/haikang/service/OrgService.java
  17. 57 0
      thyy-socket/src/main/java/org/thyy/socket/service/NursingRecordBoard.java
  18. 34 0
      thyy-utils/src/main/java/org/thyy/utils/WebThreadLocal.java

+ 3 - 3
pom.xml

@@ -17,12 +17,12 @@
 
     <properties>
         <java.version>21</java.version>
-        <thyy-utils>0.0.4</thyy-utils>
-        <thyy-socket>0.0.6</thyy-socket>
+        <thyy-utils>0.0.5</thyy-utils>
+        <thyy-socket>0.0.7</thyy-socket>
         <thyy-archive>0.0.8</thyy-archive>
         <thyy-haikang>0.0.4</thyy-haikang>
         <thyy-beinhospital>0.0.1</thyy-beinhospital>
-        <thyy-emr-query>1.4.6</thyy-emr-query>
+        <thyy-emr-query>1.5.0</thyy-emr-query>
     </properties>
     <modules>
         <module>thyy-archive</module>

+ 0 - 5
thyy-emr-query/src/main/java/org/thyy/emrquery/controller/emr/EmrQualityControlController.java

@@ -24,11 +24,6 @@ public class EmrQualityControlController {
         return service.obtainTheProportionOfMedicalRecords(startDate, endDate, finalControl);
     }
 
-    @GetMapping("/selectControlByPatNo")
-    public ResultVo<JSONObject> selectControlByPatNo(@RequestParam("patNo") String patNo, @RequestParam("times") Integer times) {
-        return service.selectControlByPatNo(patNo, times);
-    }
-
     @PostMapping("/linkControl")
     public ResultVo<JSONObject> linkControl(@RequestBody EmrQualityControlService.LinkControlParams params) {
         return service.linkControl(params);

+ 0 - 1
thyy-emr-query/src/main/java/org/thyy/emrquery/controller/timeLimitPrompt/TimeLimitPromptController.java

@@ -29,7 +29,6 @@ public class TimeLimitPromptController {
         return service.timeLimitPromptByUserCode(userCode);
     }
 
-
     @GetMapping("/timeLimitPromptByPatientNo")
     @PassToken
     public ResultVo<Map<String, List<TimeLimitPrompt>>> timeLimitPromptByPatientNo(@RequestParam("patNo") String patNo) {

+ 5 - 5
thyy-emr-query/src/main/java/org/thyy/emrquery/dao/EmrQualityControlDao.java

@@ -670,13 +670,13 @@ public interface EmrQualityControlDao {
             "       emr_id,  " +
             "       history,  " +
             "       doctor," +
-            "       emr_name = (select name from emr_patient_data where emr_audit_detail.emr_id = emr_patient_data.id),level  " +
+            "       emr_name = (select name from emr_patient_data where emr_audit_detail.emr_id = emr_patient_data.id),level,minus_points  " +
             "from emr_audit_detail with (NOLOCK) " +
-            "where pat_no = #{patNo}  " +
-            "  and times = #{times}" +
-            "  and history = 0 " +
+            "where ${ew.sqlSegment} and history = 0 " +
+            "  and final_control = (select isnull(final_control, 0)\n" +
+            "from view_zy_allpatient where inpatient_no = pat_no and times = admiss_times) " +
             " order by review_time ")
-    List<EmrAuditDetail> patientQualityControl(String patNo, Integer times);
+    List<EmrAuditDetail> patientQualityControl(@Param("ew") QueryWrapper<EmrAuditDetail> ew);
 
     @Select("select      f_dept_code as fCode, " +
             "    fDept = (select [dbo].F_GetDeptName(f_dept_code)), " +

+ 1 - 8
thyy-emr-query/src/main/java/org/thyy/emrquery/dao/timeLimitPrompt/TimeLimitPromptDao.java

@@ -27,13 +27,6 @@ public interface TimeLimitPromptDao {
             "where inpatient_no = '${code}' and inpatient_no not like 'JT%' ")
     List<PatientInfo> getPatientByPatNo(@Param("code") String code);
 
-    @Select("select top 1 count(1) " +
-            "from yz_act_order " +
-            "where inpatient_no = '${patNo}' " +
-            "  and admiss_times = ${times} " +
-            "  and status_flag in ('4', '5') " +
-            "  and order_code in (select order_code from yz_zd_order_item_confirm where item_name = N'${name}')")
-    Integer patientStatus(String patNo, Integer times, String name);
 
     @Select("select top 1 id from emr_patient_data where pat_no = '${patNo}' and times = ${times} and del_flag = 0 " +
             "and emr_category_code = 'shoucibingchengjilu'  order by create_date desc ")
@@ -102,7 +95,7 @@ public interface TimeLimitPromptDao {
             "     emr_patient_data b " +
             "where a.emr_id = b.id " +
             "  and history = 0 " +
-            "  and b.del_flag = 0 " +
+            "  and b.del_flag = 0 and a.review_time >= CAST(DATEADD(MONTH, -1, GETDATE()) AS DATE) and a.review_time <= getdate()  " +
             "  and doctor = #{doctor} " +
             "  and remediation_status is null and number_of_defects > 0" +
             "  and a.final_control = (select final_control from view_zy_patient_all c where c.inpatient_no = a.pat_no and c.admiss_times = a.times) ;")

+ 0 - 1
thyy-emr-query/src/main/java/org/thyy/emrquery/entity/emr/PatientInfo.java

@@ -12,7 +12,6 @@ import java.util.Date;
 import java.util.HashMap;
 import java.util.List;
 import java.util.Map;
-import java.util.stream.Collectors;
 
 @Data
 public class PatientInfo implements Serializable {

+ 45 - 10
thyy-emr-query/src/main/java/org/thyy/emrquery/service/emr/EmrQualityControlService.java

@@ -7,7 +7,9 @@ import com.alibaba.fastjson.JSONArray;
 import com.alibaba.fastjson.JSONObject;
 import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
 
+import lombok.AllArgsConstructor;
 import lombok.Data;
+import lombok.NoArgsConstructor;
 import lombok.extern.slf4j.Slf4j;
 import org.springframework.stereotype.Service;
 import org.thyy.emrquery.dao.EmrQualityControlDao;
@@ -20,6 +22,7 @@ import org.thyy.emrquery.utils.ListUtil;
 import org.thyy.emrquery.utils.SocketUtil;
 import org.thyy.emrquery.utils.StringUtil;
 import org.thyy.emrquery.websocket.WebSocketServer;
+import org.thyy.utils.WebThreadLocal;
 import org.thyy.utils.result.R;
 import org.thyy.utils.result.ResultVo;
 
@@ -43,6 +46,15 @@ public class EmrQualityControlService {
      */
     private final AfterTheInstructionIsGiven afterTheInstructionIsGiven;
 
+    @Data
+    @AllArgsConstructor
+    @NoArgsConstructor
+    public static class AuditParams {
+        private String startDate;
+        private String endDate;
+        private String approver;
+    }
+
     /**
      * 病程片段间隔
      */
@@ -72,7 +84,6 @@ public class EmrQualityControlService {
         return percentFormat.format(result);
     }
 
-
     public ResultVo<String> obtainTheProportionOfMedicalRecords(String startDate, String endDate, int finalControl) {
         int linkQualityControlMolecules;
         int linkQualityControlDenominator;
@@ -90,9 +101,17 @@ public class EmrQualityControlService {
         }
     }
 
+    /**
+     * 环节质控
+     *
+     * @param params 数据
+     * @return 数据
+     */
     public ResultVo<JSONObject> linkControl(LinkControlParams params) {
         List<PatientInfo> list;
         if ("intervalPatients".equals(params.getTimeType())) {
+            WebThreadLocal.create("AuditParams", new AuditParams(params.getStartDate(), params.getEndDate(), params.getApprover()));
+
             String sql = "";
             if (StringUtil.notBlank(params.getDeptCode())) {
                 sql = StrUtil.format("and zk_ward = '{}'", params.getDeptCode());
@@ -115,10 +134,12 @@ public class EmrQualityControlService {
         return R.ok(js);
     }
 
-    public ResultVo<JSONObject> selectControlByPatNo(String patNo, Integer times) {
-        return R.ok(patientEmrControlFunc(null, dao.selectControlByPatNo(patNo, times), SocketEnum.FINAL_CONTROL));
-    }
-
+    /**
+     * 终末质控的高级检索
+     *
+     * @param param
+     * @return
+     */
     public ResultVo<JSONObject> finalControlAdvancedRetrieval(FinalControlAdvancedRetrieval param) {
         StringBuilder sb = new StringBuilder();
 
@@ -178,7 +199,7 @@ public class EmrQualityControlService {
             sb.append(" and ( ")
                     .append(" dis_date >= '").append(param.getDisDate().get(0)).append("'")
                     .append(" and ")
-                    .append(" dis_date <= '").append(param.getDisDate().get(0)).append("'")
+                    .append(" dis_date <= '").append(param.getDisDate().get(1)).append("'")
                     .append(" ) ");
         }
 
@@ -199,6 +220,7 @@ public class EmrQualityControlService {
 
         if (isQualityControl) {
             sql.append(" where 1=1 ");
+            WebThreadLocal.create("AuditParams", new AuditParams(param.getStartDate(), param.getEndDate(), null));
         }
 
         if (ListUtil.notBlank(param.getDeptCode())) {
@@ -248,9 +270,6 @@ public class EmrQualityControlService {
             afterAdmission.start(item, p);
             afterTheInstructionIsGiven.start(item, p);
             fragmentInterval.start(item, p);
-            // 设置审核数据
-//            List<EmrAuditDetail> auditDetail = dao.patientQualityControl(item.getPatNo(), item.getTimes());
-//            item.setQualityControlOpinion(auditDetail);
             setAdditionalInfo(item);
             审核分组(电子病历审核分组, item);
             socket.put("current", (i + 1));
@@ -270,7 +289,22 @@ public class EmrQualityControlService {
     }
 
     private void 审核分组(List<PatientInfo> 电子病历审核分组, PatientInfo 患者) {
-        List<EmrAuditDetail> auditDetail = dao.patientQualityControl(患者.getPatNo(), 患者.getTimes());
+        AuditParams auditParams = WebThreadLocal.get("AuditParams");
+
+        QueryWrapper<EmrAuditDetail> qw = new QueryWrapper<>();
+        qw.eq("pat_no", 患者.getPatNo());
+        qw.eq("times", 患者.getTimes());
+        if (auditParams != null) {
+            qw.ge("review_time", auditParams.getStartDate());
+            qw.le("review_time", auditParams.getEndDate());
+
+            if (StrUtil.isNotBlank(auditParams.getApprover())) {
+                qw.eq("approver", auditParams.getApprover());
+            }
+        }
+
+
+        List<EmrAuditDetail> auditDetail = dao.patientQualityControl(qw);
         if (auditDetail.isEmpty()) {
             return;
         }
@@ -341,4 +375,5 @@ public class EmrQualityControlService {
 
     }
 
+
 }

+ 0 - 1
thyy-emr-query/src/main/java/org/thyy/emrquery/service/emr/electronicMedicalRecords/FragmentInterval.java

@@ -98,7 +98,6 @@ public class FragmentInterval {
             } catch (Exception ignored) {
             }
         }
-        log.info("数据:{}", JSON.toJSONString(tempDates));
     }
 
 

+ 0 - 1
thyy-emr-query/src/main/java/org/thyy/emrquery/service/timeLimitPrompt/TimeLimitPromptService.java

@@ -26,7 +26,6 @@ public class TimeLimitPromptService {
         this.dao = dao;
     }
 
-
     public ResultVo<Map<String, List<TimeLimitPrompt>>> timeLimitPromptByUserCode(String code) {
         List<PatientInfo> patInfoList = dao.getPatientByReferPhysicianCode(code);
         return 时限提示(patInfoList);

+ 1 - 1
thyy-haikang/pom.xml

@@ -8,7 +8,7 @@
         <version>0.0.1</version>
     </parent>
     <artifactId>thyy-haikang</artifactId>
-    <version>0.0.3</version>
+    <version>${thyy-haikang}</version>
     <name>thyy-haikang</name>
     <description>thyy-haikang</description>
     <properties>

+ 7 - 4
thyy-haikang/src/main/java/org/thyy/haikang/controller/DoorController.java

@@ -5,10 +5,7 @@ import io.swagger.v3.oas.annotations.Operation;
 import io.swagger.v3.oas.annotations.tags.Tag;
 import lombok.extern.slf4j.Slf4j;
 import org.springframework.validation.annotation.Validated;
-import org.springframework.web.bind.annotation.PostMapping;
-import org.springframework.web.bind.annotation.RequestBody;
-import org.springframework.web.bind.annotation.RequestMapping;
-import org.springframework.web.bind.annotation.RestController;
+import org.springframework.web.bind.annotation.*;
 import org.thyy.haikang.entity.params.door.AddFace;
 import org.thyy.haikang.entity.params.door.PatientInfo;
 import org.thyy.haikang.entity.params.door.PatNo;
@@ -65,4 +62,10 @@ public class DoorController {
         return doorService.addRegistration(params);
     }
 
+    @GetMapping("/addAllPatient")
+    @Operation(description = "同步全院患者", summary = "同步全院患者")
+    public ResultVo<String> addAllPatient() {
+        return doorService.addAllPatient();
+    }
+
 }

+ 4 - 3
thyy-haikang/src/main/java/org/thyy/haikang/controller/OrgController.java

@@ -21,10 +21,11 @@ public class OrgController {
         this.orgService = orgService;
     }
 
-    @PostMapping("/synchronizeDepartments")
+    @GetMapping("/synchronizeDepartments")
     @Operation(description = "同步本院科室", summary = "同步本院科室")
-    public ResultVo<String> synchronizeDepartments() {
-        orgService.synchronizeDepartments();
+    public ResultVo<String> synchronizeDepartments(@RequestParam(defaultValue = "6d6cdfd5-46cb-4804-b5b2-cbc2a5c21c45")
+                                                   String orgIndexCode) {
+        orgService.synchronizeDepartments(orgIndexCode);
         return R.ok();
     }
 

+ 10 - 3
thyy-haikang/src/main/java/org/thyy/haikang/dao/DoorDao.java

@@ -9,7 +9,6 @@ import java.util.List;
 
 @Mapper
 public interface DoorDao extends BaseMapper<HaikangPatient> {
-
     @Insert("""
             insert t_haikang_patient (pat_no_times, person_id)
             values (#{patNo},#{id});""")
@@ -53,7 +52,15 @@ public interface DoorDao extends BaseMapper<HaikangPatient> {
     @Delete("delete t_haikang_visitor where id = #{cardId}")
     void deleteVisitorData(String cardId);
 
-    @Select("select rtrim(inpatient_no) as patNo from zy_actpatient")
+    @Select("""
+            select rtrim(a.inpatient_no) as patNo,
+                   admiss_times          as times,
+                   a.sex                 as gender,
+                   dept                  as orgIndexCode,
+                   rtrim(a.name)         as personName,
+                   rtrim(bed_no)         as bedNo
+            from zy_actpatient a,
+                 a_patient_mi b
+            where a.inpatient_no = b.inpatient_no """)
     List<PatientInfo> getAllPatient();
-
 }

+ 3 - 3
thyy-haikang/src/main/java/org/thyy/haikang/dao/OrgDao.java

@@ -9,8 +9,8 @@ import java.util.List;
 @Mapper
 public interface OrgDao {
 
-    @Select("select rtrim(code) as orgIndexCode," +
-            "       rtrim(name) as orgName," +
-            "      parentIndexCode = 'root000000'  from zy_dept_code")
+    @Select("""
+            select rtrim(code) as orgIndexCode,
+                   rtrim(name) as orgName from zy_dept_code""")
     List<OrgBatchAdd> deptList();
 }

+ 15 - 25
thyy-haikang/src/main/java/org/thyy/haikang/service/DoorService.java

@@ -4,7 +4,6 @@ import cn.hutool.core.convert.Convert;
 import cn.hutool.core.date.DatePattern;
 import cn.hutool.core.date.DateTime;
 import cn.hutool.core.date.DateUtil;
-import cn.hutool.core.io.FileUtil;
 import cn.hutool.core.lang.Validator;
 import cn.hutool.core.text.StrFormatter;
 import cn.hutool.core.util.IdcardUtil;
@@ -12,7 +11,6 @@ import cn.hutool.crypto.asymmetric.KeyType;
 import cn.hutool.crypto.asymmetric.RSA;
 import com.alibaba.fastjson2.JSONArray;
 import com.alibaba.fastjson2.JSONObject;
-import jakarta.annotation.PostConstruct;
 import lombok.extern.slf4j.Slf4j;
 import org.springframework.stereotype.Service;
 import org.thyy.haikang.dao.DoorDao;
@@ -32,7 +30,6 @@ import org.thyy.utils.result.ResultVo;
 import java.time.LocalDateTime;
 import java.time.OffsetDateTime;
 import java.time.ZoneOffset;
-import java.util.Base64;
 import java.util.Date;
 import java.util.List;
 
@@ -41,9 +38,9 @@ import java.util.List;
 @Service
 public class DoorService {
     private final DoorDao dao;
-
     private final static String privateKey = "MIICdgIBADANBgkqhkiG9w0BAQEFAASCAmAwggJcAgEAAoGBAKAc+jzqVKHsjNdyuDGL7u6zZR55j87l+0GGT4/yEV+K8ZtL1GoIgOD6vv6eEg2iOwl6Wh6hq8XR4cIyzVyvMZ35dIw3oGN89ObtuCha7gLOmWYUIGVnkUBkLFeIdwe4F8bq1q15o7azsTVekSyNJf/wnxWMp8ibtvO41T8DIzZPAgMBAAECgYAeeLVVD4Gw2VyKij4sy8Var1CQxrDMPu+c7ktJCVguFzrZA8r2rQyeBIqB2aJ07smOibcJ+lm/Ca0N8O4tc/gcm4g/JsjBALFUmqyCkLQpRyIbz8V9uAmrLcchT74GS727Uv4KVTmQNDZTPIDdSZWSJ8S+WKmj8q3wUF1HLF1eXQJBAOC7D6xIB2XNS6Voa7C7m8aeg53lfcDUVJ6m0YFdvMbsU2cnlxnCSX1OsghFuVQLKcGeN+aXiTEileb3pAl2RC0CQQC2ZDtDb+1OmLmRNugp29Pmm8MM8KpktfqiBFi92Q747XwEeMgLi3qetq1wDT4dgvyURs2McsbF7diVtFv7DMXrAkAoYzXj3mYF86k+ps+DyZOrVF2PCOlauE4k3RIVz8TXcy1iAolzRalzbastNWqjIgZ1F3wwYtdzDyYlhifi03BZAkEArkgidPMbwDGhiAf+WhkrZz1JaTECsM9PGcergGVLsENFcQR0qstxtPz7x4lv5EVI0urA+Man93OptIsuJTr0VwJAd86EbHyOn5Lah7ptPGsmsqkrdMZcJ3chRj6pDtvb0A2lhaJfDRxmAiWCnviPhTApH6/1WRzBqc1ZTymyRTF9kA==";
     private final static String publicKey = "MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQCgHPo86lSh7IzXcrgxi+7us2UeeY/O5ftBhk+P8hFfivGbS9RqCIDg+r7+nhINojsJeloeoavF0eHCMs1crzGd+XSMN6BjfPTm7bgoWu4CzplmFCBlZ5FAZCxXiHcHuBfG6tateaO2s7E1XpEsjSX/8J8VjKfIm7bzuNU/AyM2TwIDAQAB";
+
     RSA idCardRsa = new RSA(privateKey, publicKey);
 
     public DoorService(DoorDao doorDao) {
@@ -57,6 +54,10 @@ public class DoorService {
         // 传递给海康的id必须是数字和英文
         String id = params.getPatNo() + params.getTimes();
 
+        if (params.getOrgIndexCode().contains("+")) {
+            params.setOrgIndexCode(params.getOrgIndexCode().replaceAll("\\+", "j"));
+        }
+
         SingleAdd addParams = SingleAdd.builder()
                 .personName(params.getPersonName())
                 .gender(params.getGender())
@@ -112,25 +113,6 @@ public class DoorService {
         return patientTimes;
     }
 
-    public static String padWithZeros(String input) {
-        // 如果输入字符串为空,返回10个0
-        if (input == null || input.isEmpty()) {
-            return "0000000000";
-        }
-
-        // 如果字符串长度超过10位,截断前10位
-        if (input.length() >= 10) {
-            return input.substring(0, 10);
-        }
-
-        // 在字符串后面填充0,直到达到10位
-        StringBuilder paddedString = new StringBuilder(input);
-        while (paddedString.length() < 10) {
-            paddedString.append('0');
-        }
-        return paddedString.toString();
-    }
-
     /**
      * 删除患者
      *
@@ -263,9 +245,7 @@ public class DoorService {
                 ;
             }
         } catch (Exception ignore) {
-
         }
-
         JSONObject post = RequestUtils.post("/api/iccm/v1/appointment/free/registration", body);
         dao.deleteVisitorData(params.getCertificateNo());
         dao.insertVisitorData(params.getCertificateNo(), post.toJSONString());
@@ -329,4 +309,14 @@ public class DoorService {
         return date.format(dtf2);
     }
 
+    public ResultVo<String> addAllPatient() {
+        List<PatientInfo> allPatient = dao.getAllPatient();
+        allPatient.forEach(item -> {
+            TryUtil.ignoreErr(() -> {
+                createPatient(item);
+            });
+        });
+        return R.ok();
+    }
+
 }

+ 9 - 2
thyy-haikang/src/main/java/org/thyy/haikang/service/OrgService.java

@@ -19,10 +19,17 @@ public class OrgService {
         this.orgDao = orgDao;
     }
 
-    public void synchronizeDepartments() {
+    public void synchronizeDepartments(String orgIndexCode) {
         List<OrgBatchAdd> codeNames = orgDao.deptList();
+
+        codeNames.forEach(item -> {
+            if (item.getOrgIndexCode().contains("+")) {
+                item.setOrgIndexCode(item.getOrgIndexCode().replaceAll("\\+", "j"));
+            }
+            item.setParentIndexCode(orgIndexCode);
+        });
+
         Object post = RequestUtils.post("/api/resource/v1/org/batch/add", JSONObject.toJSONString(codeNames));
         log.info("同步数据:{}", post.toString());
     }
-
 }

+ 57 - 0
thyy-socket/src/main/java/org/thyy/socket/service/NursingRecordBoard.java

@@ -0,0 +1,57 @@
+package org.thyy.socket.service;
+
+import cn.hutool.core.util.IdUtil;
+import com.alibaba.fastjson2.JSONObject;
+import lombok.extern.slf4j.Slf4j;
+import org.springframework.stereotype.Component;
+import org.springframework.web.socket.WebSocketSession;
+
+import java.util.ArrayList;
+import java.util.List;
+import java.util.Map;
+import java.util.concurrent.ConcurrentHashMap;
+
+@Component
+@Slf4j
+public class NursingRecordBoard implements Business {
+
+    private final Map<String, List<WebSocketSession>> rooms = new ConcurrentHashMap<>();
+
+    @Override
+    public void onOpen(WebSocketSession session, String sid) {
+        rooms.computeIfAbsent(sid, k -> new ArrayList<>())
+                .add(session);
+    }
+
+    @Override
+    public void onClose(WebSocketSession session, String sid) {
+        rooms.get(sid).remove(session);
+        if (rooms.get(sid).isEmpty()) {
+            rooms.remove(sid);
+        }
+    }
+
+    @Override
+    public void onMessage(WebSocketSession session, String sid, String data) {
+        if (data.equals("ping")) {
+            Business.send(session, "pong");
+        }
+    }
+
+    @Override
+    public void sendRoom(JSONObject json) {
+        String ward = json.getString("ward");
+        String isCall = json.getString("state");
+        List<WebSocketSession> webSocketSessions = rooms.get(ward);
+        if (webSocketSessions == null) {
+            return;
+        }
+        webSocketSessions.forEach(session -> {
+            Business.send(session, isCall, json);
+        });
+    }
+
+    public static void main(String[] args) {
+        System.out.println(IdUtil.fastSimpleUUID());
+    }
+}

+ 34 - 0
thyy-utils/src/main/java/org/thyy/utils/WebThreadLocal.java

@@ -0,0 +1,34 @@
+package org.thyy.utils;
+
+import org.springframework.web.context.request.RequestAttributes;
+import org.springframework.web.context.request.RequestContextHolder;
+
+public class WebThreadLocal {
+
+    private static void checkRequestContext() {
+        try {
+            RequestContextHolder.currentRequestAttributes();
+        } catch (IllegalStateException e) {
+            throw new IllegalStateException("必须在Web请求线程中调用!");
+        }
+    }
+
+    private static String getKeyName(String name) {
+        return "web-thread-local-" + name;
+    }
+
+    public static <T> void create(String name, T value) {
+        checkRequestContext();
+        RequestContextHolder
+                .currentRequestAttributes()
+                .setAttribute(getKeyName(name), value, RequestAttributes.SCOPE_REQUEST);
+    }
+
+    @SuppressWarnings("unchecked")
+    public static <T> T get(String name) {
+        checkRequestContext();
+        return (T) RequestContextHolder
+                .currentRequestAttributes()
+                .getAttribute(getKeyName(name), RequestAttributes.SCOPE_REQUEST);
+    }
+}