Ver Fonte

Merge remote-tracking branch 'origin/dev' into zsl

# Conflicts:
#	coffee-system/src/main/java/com/coffee/bus/controller/BusDeviceController.java
#	coffee-system/src/main/java/com/coffee/bus/mapper/BusDeviceAlarmMapper.java
#	coffee-system/src/main/java/com/coffee/bus/service/LocalBusDeviceAlarmService.java
15638522405 há 3 anos atrás
pai
commit
1ea0e0a65f
100 ficheiros alterados com 3254 adições e 910 exclusões
  1. 5 0
      coffee-admin/Dockerfile
  2. 2 1
      coffee-admin/src/main/resources/application.yml
  3. 12 1
      coffee-admin/src/test/java/com/coffee/admin/BusClinicTest.java
  4. 1 1
      coffee-admin/src/test/java/com/coffee/admin/BusDeviceTest.java
  5. 3 1
      coffee-admin/src/test/java/com/coffee/admin/BusHospitalTest.java
  6. 49 4
      coffee-admin/src/test/java/com/coffee/admin/BusPatientTest.java
  7. 120 0
      coffee-admin/src/test/java/com/coffee/admin/HisStrategyTest.java
  8. 1 1
      coffee-common/src/main/java/com/coffee/common/config/CachingContentFilter.java
  9. 30 12
      coffee-common/src/main/java/com/coffee/common/config/websocket/DefaultMessageListener.java
  10. 6 3
      coffee-common/src/main/java/com/coffee/common/config/websocket/DefaultWebSocketMsgHandler.java
  11. 6 3
      coffee-common/src/main/java/com/coffee/common/config/websocket/MessageResponse.java
  12. 3 4
      coffee-common/src/main/java/com/coffee/common/config/websocket/MessagingRequest.java
  13. 51 42
      coffee-common/src/main/java/com/coffee/common/config/websocket/WebSocketConstant.java
  14. 100 43
      coffee-common/src/main/java/com/coffee/common/config/websocket/handler/Subscribe.java
  15. 24 0
      coffee-common/src/main/java/com/coffee/common/config/websocket/handler/TopicWrapper.java
  16. 9 0
      coffee-common/src/main/java/com/coffee/common/config/websocket/handler/WsHandler.java
  17. 19 3
      coffee-common/src/main/java/com/coffee/common/crud/BaseService.java
  18. 5 3
      coffee-common/src/main/java/com/coffee/common/crud/controller/BaseSaveController.java
  19. 9 0
      coffee-common/src/main/java/com/coffee/common/entity/GenericEntity.java
  20. 7 5
      coffee-common/src/main/java/com/coffee/common/redis/RedisConfig.java
  21. 36 1
      coffee-framework/src/main/java/com/coffee/framework/config/WebAppMvcConfig.java
  22. 2 5
      coffee-system/src/main/java/com/coffee/aliyun/AliyunConsumerGroupService.java
  23. 3 0
      coffee-system/src/main/java/com/coffee/aliyun/AliyunIotSubscribeClient.java
  24. 14 13
      coffee-system/src/main/java/com/coffee/bus/controller/BusAlarmController.java
  25. 92 21
      coffee-system/src/main/java/com/coffee/bus/controller/BusClinicController.java
  26. 0 19
      coffee-system/src/main/java/com/coffee/bus/controller/BusConstantController.java
  27. 104 5
      coffee-system/src/main/java/com/coffee/bus/controller/BusDeviceController.java
  28. 17 0
      coffee-system/src/main/java/com/coffee/bus/controller/BusDeviceHistoryController.java
  29. 5 1
      coffee-system/src/main/java/com/coffee/bus/controller/BusDeviceManualController.java
  30. 1 0
      coffee-system/src/main/java/com/coffee/bus/controller/BusDeviceRunningController.java
  31. 18 2
      coffee-system/src/main/java/com/coffee/bus/controller/BusEvaluationController.java
  32. 9 0
      coffee-system/src/main/java/com/coffee/bus/controller/BusHospitalController.java
  33. 125 48
      coffee-system/src/main/java/com/coffee/bus/controller/BusPatientController.java
  34. 4 1
      coffee-system/src/main/java/com/coffee/bus/controller/vo/ClinicStatsVo.java
  35. 21 0
      coffee-system/src/main/java/com/coffee/bus/controller/vo/GetPatientInfoVo.java
  36. 4 1
      coffee-system/src/main/java/com/coffee/bus/controller/vo/MonitorFinishedVo.java
  37. 13 2
      coffee-system/src/main/java/com/coffee/bus/entity/BusClinicEntity.java
  38. 94 19
      coffee-system/src/main/java/com/coffee/bus/entity/BusDeviceAlarmEntity.java
  39. 13 2
      coffee-system/src/main/java/com/coffee/bus/entity/BusDeviceEntity.java
  40. 0 1
      coffee-system/src/main/java/com/coffee/bus/entity/BusDeviceManualEntity.java
  41. 33 4
      coffee-system/src/main/java/com/coffee/bus/entity/BusDeviceRunningEntity.java
  42. 14 3
      coffee-system/src/main/java/com/coffee/bus/entity/BusEvaluationEntity.java
  43. 53 3
      coffee-system/src/main/java/com/coffee/bus/entity/BusHospitalEntity.java
  44. 6 3
      coffee-system/src/main/java/com/coffee/bus/entity/BusInfusionHistoryEntity.java
  45. 114 4
      coffee-system/src/main/java/com/coffee/bus/entity/BusInfusionModifyEntity.java
  46. 0 13
      coffee-system/src/main/java/com/coffee/bus/entity/BusPatientEntity.java
  47. 2 0
      coffee-system/src/main/java/com/coffee/bus/entity/PatientDeviceRepeatDomain.java
  48. 0 230
      coffee-system/src/main/java/com/coffee/bus/entity/PatientMonitorDomain.java
  49. 4 10
      coffee-system/src/main/java/com/coffee/bus/entity/common/CommonDeviceParam.java
  50. 1 0
      coffee-system/src/main/java/com/coffee/bus/enums/ConfigEnum.java
  51. 1 6
      coffee-system/src/main/java/com/coffee/bus/enums/DeviceAlarmEnum.java
  52. 1 0
      coffee-system/src/main/java/com/coffee/bus/enums/DeviceManualEnum.java
  53. 2 1
      coffee-system/src/main/java/com/coffee/bus/enums/DeviceStatusEnum.java
  54. 1 1
      coffee-system/src/main/java/com/coffee/bus/enums/DeviceTypeEnum.java
  55. 81 0
      coffee-system/src/main/java/com/coffee/bus/his/HisRequest.java
  56. 73 0
      coffee-system/src/main/java/com/coffee/bus/his/HisResponse.java
  57. 331 0
      coffee-system/src/main/java/com/coffee/bus/his/HisScriptSession.java
  58. 82 0
      coffee-system/src/main/java/com/coffee/bus/his/HisScriptSessionManager.java
  59. 25 0
      coffee-system/src/main/java/com/coffee/bus/his/strategy/HisStrategyEnum.java
  60. 49 0
      coffee-system/src/main/java/com/coffee/bus/his/strategy/HisStrategyHandler.java
  61. 30 0
      coffee-system/src/main/java/com/coffee/bus/his/strategy/HisStrategyManager.java
  62. 36 0
      coffee-system/src/main/java/com/coffee/bus/his/strategy/HisStrategyManagerRegister.java
  63. 68 0
      coffee-system/src/main/java/com/coffee/bus/his/strategy/all/EqualsStrategyHandler.java
  64. 13 0
      coffee-system/src/main/java/com/coffee/bus/his/strategy/all/HisAllStrategyHandler.java
  65. 36 0
      coffee-system/src/main/java/com/coffee/bus/his/strategy/all/HisAllStrategyManager.java
  66. 60 0
      coffee-system/src/main/java/com/coffee/bus/his/strategy/all/LessToMoreHisStrategyHandler.java
  67. 75 0
      coffee-system/src/main/java/com/coffee/bus/his/strategy/all/MoreToLessHisStrategyHandler.java
  68. 78 0
      coffee-system/src/main/java/com/coffee/bus/his/strategy/onlynew/DefaultHisNewStrategyHandler.java
  69. 13 0
      coffee-system/src/main/java/com/coffee/bus/his/strategy/onlynew/HisNewStrategyHandler.java
  70. 32 0
      coffee-system/src/main/java/com/coffee/bus/his/strategy/onlynew/HisNewStrategyManager.java
  71. 90 0
      coffee-system/src/main/java/com/coffee/bus/his/strategy/part/DefaultHisPartStrategyHandler.java
  72. 13 0
      coffee-system/src/main/java/com/coffee/bus/his/strategy/part/HisPartStrategyHandler.java
  73. 32 0
      coffee-system/src/main/java/com/coffee/bus/his/strategy/part/HisPartStrategyManager.java
  74. 5 3
      coffee-system/src/main/java/com/coffee/bus/listener/event/bean/HisEvent.java
  75. 14 0
      coffee-system/src/main/java/com/coffee/bus/mapper/BusClinicMapper.java
  76. 6 1
      coffee-system/src/main/java/com/coffee/bus/mapper/BusDeviceAlarmMapper.java
  77. 8 0
      coffee-system/src/main/java/com/coffee/bus/mapper/BusDeviceHistoryMapper.java
  78. 3 1
      coffee-system/src/main/java/com/coffee/bus/mapper/BusDeviceManualMapper.java
  79. 6 0
      coffee-system/src/main/java/com/coffee/bus/mapper/BusDeviceMapper.java
  80. 5 0
      coffee-system/src/main/java/com/coffee/bus/mapper/BusEvaluationMapper.java
  81. 4 2
      coffee-system/src/main/java/com/coffee/bus/mapper/BusPatientMapper.java
  82. 0 8
      coffee-system/src/main/java/com/coffee/bus/registry/Operator.java
  83. 4 87
      coffee-system/src/main/java/com/coffee/bus/registry/device/ClusterDeviceOperator.java
  84. 4 1
      coffee-system/src/main/java/com/coffee/bus/registry/device/ClusterDeviceRegistry.java
  85. 2 2
      coffee-system/src/main/java/com/coffee/bus/registry/device/DeviceOperator.java
  86. 18 81
      coffee-system/src/main/java/com/coffee/bus/registry/patient/ClusterPatientOperator.java
  87. 63 27
      coffee-system/src/main/java/com/coffee/bus/registry/patient/ClusterPatientRegistry.java
  88. 0 2
      coffee-system/src/main/java/com/coffee/bus/registry/patient/PatientOperator.java
  89. 6 0
      coffee-system/src/main/java/com/coffee/bus/registry/patient/PatientRegistry.java
  90. 2 10
      coffee-system/src/main/java/com/coffee/bus/script/ScriptManager.java
  91. 142 14
      coffee-system/src/main/java/com/coffee/bus/service/LocalBusClinicService.java
  92. 6 48
      coffee-system/src/main/java/com/coffee/bus/service/LocalBusDeviceAlarmService.java
  93. 9 0
      coffee-system/src/main/java/com/coffee/bus/service/LocalBusDeviceHistoryService.java
  94. 56 3
      coffee-system/src/main/java/com/coffee/bus/service/LocalBusDeviceManualService.java
  95. 20 20
      coffee-system/src/main/java/com/coffee/bus/service/LocalBusDeviceRunningService.java
  96. 111 18
      coffee-system/src/main/java/com/coffee/bus/service/LocalBusDeviceService.java
  97. 7 0
      coffee-system/src/main/java/com/coffee/bus/service/LocalBusEvaluationService.java
  98. 51 16
      coffee-system/src/main/java/com/coffee/bus/service/LocalBusHospitalService.java
  99. 44 0
      coffee-system/src/main/java/com/coffee/bus/service/LocalBusInfusionHistoryService.java
  100. 172 20
      coffee-system/src/main/java/com/coffee/bus/service/LocalBusPatientService.java

+ 5 - 0
coffee-admin/Dockerfile

@@ -2,6 +2,11 @@ FROM docker.io/java:8
 
 ADD target/coffee-admin.jar /pump.jar
 RUN bash -c "touch /pump.jar"
+ENV TZ 'Asia/Shanghai'
+ENV LANG en_US.UTF-8
+ENV LANGUAGE en_US:en
+ENV LC_ALL en_US.UTF-8
+
 #ENTRYPOINT ["java","-Djava.security.egd=file:/dev/./urandom","-jar","/pump.jar"]
 ENTRYPOINT ["java", "-jar", "/pump.jar"]
 EXPOSE 9090

+ 2 - 1
coffee-admin/src/main/resources/application.yml

@@ -65,12 +65,13 @@ mybatis-plus:
       idType: ASSIGN_ID
   configuration:
     log-impl: org.apache.ibatis.logging.nologging.NoLoggingImpl
+#    log-impl: org.apache.ibatis.logging.stdout.StdOutImpl
     default-enum-type-handler: com.baomidou.mybatisplus.core.handlers.MybatisEnumTypeHandler
   type-aliases-package: com.coffee.bus.entity
 
 # 阿里云对接配置
 aliyun:
   server-subscription:
-    enable: false  # 是否开启阿里云物联网服务端订阅
+    enable: true  # 是否开启阿里云物联网服务端订阅
   product:
     productKey: a1ALlsBa2ZK

+ 12 - 1
coffee-admin/src/test/java/com/coffee/admin/BusClinicTest.java

@@ -1,5 +1,6 @@
 package com.coffee.admin;
 
+import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
 import com.coffee.bus.controller.vo.ClinicStatsVo;
 import com.coffee.bus.entity.BusDeviceRunningEntity;
 import com.coffee.bus.entity.BusInfusionHistoryEntity;
@@ -14,6 +15,9 @@ import org.springframework.boot.test.context.SpringBootTest;
 import org.springframework.context.ApplicationContext;
 import org.springframework.test.context.junit4.SpringRunner;
 
+import java.util.List;
+import java.util.Map;
+
 /**
  * @Author longsanlang
  * @Date 2022-04-06 17:55:44
@@ -28,6 +32,8 @@ public class BusClinicTest {
     private LocalBusClinicService clinicService;
 
 
+    @Autowired
+    private LocalBusInfusionHistoryService infusionHistoryService;
 
     @Test
     public void stats(){
@@ -44,7 +50,12 @@ public class BusClinicTest {
 
     @Test
     public void save(){
-
+        List<Map<String, Object>> mapList = infusionHistoryService
+                .listMaps(new QueryWrapper<BusInfusionHistoryEntity>()
+                        .select("clinic_id","count(1) as c")
+                        .lambda()
+                        .groupBy(BusInfusionHistoryEntity::getClinicId));
+        System.out.println(mapList);
     }
 
 

+ 1 - 1
coffee-admin/src/test/java/com/coffee/admin/BusDeviceTest.java

@@ -30,7 +30,7 @@ public class BusDeviceTest {
         device.setDeviceId("12345678910");
         device.setCreateBy("auto");
         device.setCreateTime(new Date());
-        deviceService.saveByDeviceId(device);
+        deviceService.saveDevice(device);
 
     }
 

+ 3 - 1
coffee-admin/src/test/java/com/coffee/admin/BusHospitalTest.java

@@ -5,6 +5,7 @@ import com.coffee.bus.bean.Script;
 import com.coffee.bus.controller.BusHospitalController;
 import com.coffee.bus.entity.BusHospitalEntity;
 import com.coffee.bus.service.LocalBusHospitalService;
+import com.coffee.bus.utils.CodeUtils;
 import com.coffee.common.result.R;
 import org.junit.Test;
 import org.junit.runner.RunWith;
@@ -49,7 +50,8 @@ public class BusHospitalTest {
     @Test
     public void query(){
         List<BusHospitalEntity> list = busHospitalService.list();
-        System.out.println(list);
+        list.forEach(busHospitalEntity -> busHospitalEntity.setCode(CodeUtils.genInviteCode(Long.valueOf(busHospitalEntity.getId()))));
+        busHospitalService.updateBatchById(list);
     }
 
     @Test

+ 49 - 4
coffee-admin/src/test/java/com/coffee/admin/BusPatientTest.java

@@ -1,18 +1,23 @@
 package com.coffee.admin;
 
+import cn.hutool.core.date.DateField;
 import cn.hutool.core.date.DateUtil;
 import cn.hutool.core.util.EnumUtil;
 import cn.hutool.core.util.RandomUtil;
+import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
 import com.coffee.bus.controller.BusDeviceManualController;
 import com.coffee.bus.controller.vo.DeviceManualVo;
 import com.coffee.bus.entity.BusClinicEntity;
 import com.coffee.bus.entity.BusDeviceManualEntity;
 import com.coffee.bus.entity.BusPatientEntity;
 import com.coffee.bus.enums.DeviceManualEnum;
+import com.coffee.bus.his.strategy.all.EqualsStrategyHandler;
+import com.coffee.bus.his.strategy.all.HisAllStrategyHandler;
 import com.coffee.bus.service.LocalBusClinicService;
 import com.coffee.bus.service.LocalBusPatientService;
 import com.coffee.bus.service.dto.PatientDeviceRepeatResult;
 import com.coffee.common.enums.SexEnum;
+import org.hibernate.validator.constraints.Length;
 import org.junit.Test;
 import org.junit.runner.RunWith;
 import org.springframework.beans.factory.annotation.Autowired;
@@ -21,10 +26,8 @@ import org.springframework.test.context.junit4.SpringRunner;
 
 import java.io.UnsupportedEncodingException;
 import java.math.BigDecimal;
-import java.util.Arrays;
-import java.util.Date;
-import java.util.List;
-import java.util.Random;
+import java.util.*;
+import java.util.stream.Collectors;
 
 /**
  * @author lifang
@@ -42,6 +45,8 @@ public class BusPatientTest {
     @Autowired
     private LocalBusClinicService clinicService;
 
+    @Autowired
+    private EqualsStrategyHandler equalsStrategyHandler;
     @Autowired
     private BusDeviceManualController manualController;
     @Test
@@ -82,6 +87,45 @@ public class BusPatientTest {
         }
     }
 
+    @Test
+    public void fill(){
+        List<BusClinicEntity> clinicList = clinicService.list(new QueryWrapper<BusClinicEntity>().lambda().eq(BusClinicEntity::getMonitorType, true));
+        Map<String, List<BusClinicEntity>> groupByHospital = clinicList.stream().collect(Collectors.groupingBy(BusClinicEntity::getTenantId));
+        groupByHospital.forEach((tenantId,list)->{
+            Map< String, List<BusClinicEntity>> groupByPatientCode = list.stream().collect(Collectors.groupingBy(BusClinicEntity::getPatientCode));
+            groupByPatientCode.forEach((k,targets)->{
+                List<BusClinicEntity> source = new ArrayList<>();
+                for (BusClinicEntity target : targets) {
+                    BusClinicEntity clinic = new BusClinicEntity();
+                    clinic.setStartTime(target.getStartTime()==null?
+                            RandomUtil.randomDate(DateUtil.beginOfMonth(new Date()), DateField.HOUR,-30,30):target.getStartTime());
+                    clinic.setName(clinicNames.get(RandomUtil.randomInt(clinicNames.size()-1)));
+                    clinic.setPatientName(getName());
+                    clinic.setPatientGender(EnumUtil.likeValueOf(SexEnum.class,RandomUtil.randomInt(1,2)));
+                    clinic.setBedNo(target.getBedNo());
+                    clinic.setWard(target.getWard());
+                    clinic.setWeight(String.valueOf(RandomUtil.randomInt(90,150)));
+                    clinic.setWeight(String.valueOf(RandomUtil.randomInt(150,200)));
+                    clinic.setAnaDoctor(getName());
+                    clinic.setAnaType(anaTypes.get(RandomUtil.randomInt(anaTypes.size()-1)));
+                    clinic.setAnalType(analTypes.get(RandomUtil.randomInt(analTypes.size()-1)));
+                    clinic.setSurgeryDoctor(getName());
+                    clinic.setConfigPerson(getName());
+                    clinic.setPatientCode(target.getPatientCode());
+                    clinic.setMonitorType(true);
+                    clinic.setTenantId("1");
+                    source.add(clinic);
+                }
+                equalsStrategyHandler.handle(source,targets);
+            });
+
+        });
+
+    }
+    public void fillPatientCode(){
+        List<BusPatientEntity> list = patientService.list();
+    }
+
     @Test
     public void manualSave(){
         for (int i = 0; i < 30; i++) {
@@ -89,6 +133,7 @@ public class BusPatientTest {
             BusClinicEntity clinic = new BusClinicEntity();
             clinic.setStartTime(new Date());
             clinic.setName(clinicNames.get(RandomUtil.randomInt(clinicNames.size()-1)));
+            clinic.setPatientAge(RandomUtil.randomInt(15,50));
             clinic.setPatientName(getName());
             clinic.setPatientGender(EnumUtil.likeValueOf(SexEnum.class,RandomUtil.randomInt(1,2)));
             clinic.setBedNo(String.valueOf(RandomUtil.randomInt(10,100)));

+ 120 - 0
coffee-admin/src/test/java/com/coffee/admin/HisStrategyTest.java

@@ -0,0 +1,120 @@
+package com.coffee.admin;
+
+import cn.hutool.core.date.DateField;
+import cn.hutool.core.date.DateUtil;
+import cn.hutool.core.util.EnumUtil;
+import cn.hutool.core.util.RandomUtil;
+import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
+import com.coffee.bus.entity.BusClinicEntity;
+import com.coffee.bus.entity.BusDeviceEntity;
+import com.coffee.bus.his.strategy.HisStrategyEnum;
+import com.coffee.bus.his.strategy.HisStrategyHandler;
+import com.coffee.bus.his.strategy.HisStrategyManager;
+import com.coffee.bus.his.strategy.HisStrategyManagerRegister;
+import com.coffee.bus.service.LocalBusClinicService;
+import com.coffee.bus.service.LocalBusDeviceService;
+import com.coffee.common.enums.SexEnum;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.boot.test.context.SpringBootTest;
+import org.springframework.test.context.junit4.SpringRunner;
+
+import java.util.ArrayList;
+import java.util.Date;
+import java.util.List;
+
+import static com.coffee.admin.BusPatientTest.getName;
+
+/**
+ * @Author XX
+ * @Date 2022-04-25 19:00:10
+ * @Version 1.0
+ * @Description XXX
+ */
+@RunWith(SpringRunner.class)
+@SpringBootTest(classes = AdminApplication.class)
+public class HisStrategyTest {
+
+    @Autowired
+    HisStrategyManagerRegister managerRegister;
+
+    @Autowired
+    LocalBusClinicService clinicService;
+
+    String patientCode="120263";
+    String tenantId="1";
+    @Test
+    public void allEquals(){
+        HisStrategyManager<? extends HisStrategyHandler> hisStrategyManager = managerRegister.get(HisStrategyEnum.ALL);
+
+    }
+
+
+    @Test
+    public void allMoreToLess(){
+        HisStrategyManager<? extends HisStrategyHandler> hisStrategyManager = managerRegister.get(HisStrategyEnum.ALL);
+        List<BusClinicEntity> sources = new ArrayList<>();
+        List<BusClinicEntity> targets = clinicService.list(new QueryWrapper<BusClinicEntity>().lambda().eq(BusClinicEntity::getPatientCode, patientCode).eq(BusClinicEntity::getTenantId, tenantId));
+        for (BusClinicEntity target : targets) {
+            BusClinicEntity clinic = new BusClinicEntity();
+            clinic.setStartTime(target.getStartTime()==null?
+                    RandomUtil.randomDate(DateUtil.beginOfMonth(new Date()), DateField.HOUR,-30,30):DateUtil.date(target.getStartTime()).offset(DateField.HOUR_OF_DAY,-1));
+            clinic.setName(BusPatientTest.clinicNames.get(RandomUtil.randomInt(BusPatientTest.clinicNames.size()-1)));
+            clinic.setPatientName(getName());
+            clinic.setPatientGender(EnumUtil.likeValueOf(SexEnum.class,RandomUtil.randomInt(1,2)));
+            clinic.setBedNo(target.getBedNo());
+            clinic.setWard(target.getWard());
+            clinic.setWeight(String.valueOf(RandomUtil.randomInt(90,150)));
+            clinic.setWeight(String.valueOf(RandomUtil.randomInt(150,200)));
+            clinic.setAnaDoctor(getName());
+            clinic.setAnaType(BusPatientTest.anaTypes.get(RandomUtil.randomInt(BusPatientTest.anaTypes.size()-1)));
+            clinic.setAnalType(BusPatientTest.analTypes.get(RandomUtil.randomInt(BusPatientTest.analTypes.size()-1)));
+            clinic.setSurgeryDoctor(getName());
+            clinic.setConfigPerson(getName());
+            clinic.setPatientCode(target.getPatientCode());
+            clinic.setMonitorType(true);
+            clinic.setTenantId("1");
+            sources.add(clinic);
+        }
+        BusClinicEntity clinic = new BusClinicEntity();
+        clinic.setStartTime(DateUtil.beginOfDay(new Date()));
+        clinic.setName(BusPatientTest.clinicNames.get(RandomUtil.randomInt(BusPatientTest.clinicNames.size()-1)));
+        clinic.setPatientName(getName());
+        clinic.setPatientGender(EnumUtil.likeValueOf(SexEnum.class,RandomUtil.randomInt(1,2)));
+        clinic.setBedNo("10");
+        clinic.setWard("10");
+        clinic.setWeight(String.valueOf(RandomUtil.randomInt(90,150)));
+        clinic.setWeight(String.valueOf(RandomUtil.randomInt(150,200)));
+        clinic.setAnaDoctor(getName());
+        clinic.setAnaType(BusPatientTest.anaTypes.get(RandomUtil.randomInt(BusPatientTest.anaTypes.size()-1)));
+        clinic.setAnalType(BusPatientTest.analTypes.get(RandomUtil.randomInt(BusPatientTest.analTypes.size()-1)));
+        clinic.setSurgeryDoctor(getName());
+        clinic.setConfigPerson(getName());
+        clinic.setPatientCode(patientCode);
+        clinic.setMonitorType(true);
+        clinic.setTenantId("1");
+        sources.add(clinic);
+        hisStrategyManager.getHandlers()
+                .stream()
+                .filter(handler-> handler.apply(sources,targets))
+                .forEach(handler->handler.handle(sources,targets));
+    }
+
+
+    @Test
+    public void allLessToMore(){
+        HisStrategyManager<? extends HisStrategyHandler> hisStrategyManager = managerRegister.get(HisStrategyEnum.ALL);
+
+    }
+    @Test
+    public void onlyNew(){
+        HisStrategyManager<? extends HisStrategyHandler> hisStrategyManager = managerRegister.get(HisStrategyEnum.NEW);
+
+    }
+
+    @Test
+    public void part(){
+        HisStrategyManager<? extends HisStrategyHandler> hisStrategyManager = managerRegister.get(HisStrategyEnum.PART);
+    }
+}

+ 1 - 1
coffee-common/src/main/java/com/coffee/common/config/CachingContentFilter.java

@@ -16,7 +16,7 @@ import java.io.IOException;
  * @createTime 2022年04月22日 14:59:00
  */
 @Slf4j
-@WebFilter(urlPatterns = "/*")
+@WebFilter(urlPatterns = "/*",asyncSupported = true)
 public class CachingContentFilter implements Filter {
 
     @Override

+ 30 - 12
coffee-common/src/main/java/com/coffee/common/config/websocket/DefaultMessageListener.java

@@ -1,19 +1,23 @@
 package com.coffee.common.config.websocket;
 
 import cn.hutool.core.collection.CollectionUtil;
+import cn.hutool.json.JSONObject;
 import cn.hutool.json.JSONUtil;
-import com.coffee.common.result.R;
-import lombok.AllArgsConstructor;
+import com.coffee.common.cache.value.Value;
+import com.coffee.common.config.websocket.handler.TopicWrapper;
+import com.fasterxml.jackson.core.JsonProcessingException;
+import com.fasterxml.jackson.databind.ObjectMapper;
 import lombok.Data;
 import lombok.extern.slf4j.Slf4j;
 import org.springframework.data.redis.connection.Message;
 import org.springframework.data.redis.connection.MessageListener;
-import org.springframework.util.SerializationUtils;
 import org.tio.core.ChannelContext;
 import org.tio.core.Tio;
+import org.tio.core.utils.TioUtils;
+import org.tio.websocket.common.WsPacket;
 import org.tio.websocket.common.WsResponse;
 
-import java.io.UnsupportedEncodingException;
+import java.util.HashSet;
 import java.util.Set;
 
 /**
@@ -27,18 +31,32 @@ import java.util.Set;
 @Slf4j
 public class DefaultMessageListener implements MessageListener {
     private final String id;
-    private final Set<ChannelContext> channelContexts;
-
-
+    private final TopicWrapper topicWrapper;
+    private final ObjectMapper objectMapper;
+    private final  Set<ChannelContext> channelContexts;
     @Override
     public void onMessage(Message message, byte[] pattern) {
         if (CollectionUtil.isNotEmpty(channelContexts)) {
+            Set<ChannelContext> closeChannel = new HashSet<>();
             channelContexts.parallelStream()
-                    .filter(channelContext -> !channelContext.isClosed)
-                    .forEach(channel -> Tio.send(channel,
-                            WsResponse.fromText(JSONUtil.toJsonStr(R.success(
-                                    MessageResponse.of(id,"result",new String(message.getBody()))))
-                                    ,"utf-8")));
+                    .forEach(channel -> {
+                        if (!TioUtils.checkBeforeIO(channel)) {
+                            closeChannel.add(channel);
+                            return;
+                        }
+                        String json = null;
+                        try {
+                            JSONObject jsonObject = JSONUtil.parseObj(message.toString());
+                            json = objectMapper.writeValueAsString(MessageResponse.of(id, "result", Value.simple( jsonObject.get("param")).asString(),
+                                    JSONUtil.parse(jsonObject.get("message"))));
+                            Tio.send(channel,WsResponse.fromText(json, WsPacket.CHARSET_NAME));
+                        } catch (JsonProcessingException e) {
+                            log.error("ws消息订阅,解析失败,message:【】",message.toString());
+                        }
+                            }
+                    );
+            channelContexts.removeAll(closeChannel);
         }
     }
+
 }

+ 6 - 3
coffee-common/src/main/java/com/coffee/common/config/websocket/DefaultWebSocketMsgHandler.java

@@ -6,6 +6,7 @@ import cn.hutool.core.util.StrUtil;
 import cn.hutool.json.JSONUtil;
 import com.coffee.common.Constants;
 import com.coffee.common.bo.LoginUser;
+import com.coffee.common.cache.value.Value;
 import com.coffee.common.config.websocket.handler.WsHandler;
 import com.coffee.common.result.R;
 import lombok.AllArgsConstructor;
@@ -43,7 +44,6 @@ public class DefaultWebSocketMsgHandler implements IWsMsgHandler {
         if(StrUtil.isNullOrUndefined(authorization)){
             Tio.send(channelContext,WsResponse.fromText(JSONUtil.toJsonStr(R.fail("授权失败")),"utf-8"));
             //给返回信息一些时间 todo
-            Thread.sleep(50);
             channelContext.setClosed(true);
             return;
         }
@@ -89,10 +89,12 @@ public class DefaultWebSocketMsgHandler implements IWsMsgHandler {
             return null;
         }
         try {
+            synchronized (channelContext){
             if(log.isDebugEnabled()){
                 log.debug("websocket 接收到消息,message:{},token:{},userId:{}",message,channelContext.getToken(),JSONUtil.toJsonStr(channelContext.get(Constants.LOGIN_USER_KEY)));
             }
             MessagingRequest messagingRequest = JSONUtil.toBean(message, MessagingRequest.class);
+
             messagingRequest.validate();
             List<WsHandler> collect = messageHandlers
                     .parallelStream()
@@ -104,9 +106,10 @@ public class DefaultWebSocketMsgHandler implements IWsMsgHandler {
                 channelContext.setClosed(true);
                 return null;
             }
-            collect.forEach(handler->handler.onMessage(messagingRequest,channelContext));
+
+                collect.forEach(handler->handler.onMessage(messagingRequest,channelContext));
+            }
         }catch (Exception e){
-            e.printStackTrace();
             log.warn("websocket 接收到异常请求,token:{},message:{},userId:{}",channelContext.getToken(),message,JSONUtil.toJsonStr(channelContext.get(Constants.LOGIN_USER_KEY)));
             unbind(channelContext);
             channelContext.setClosed(true);

+ 6 - 3
coffee-common/src/main/java/com/coffee/common/config/websocket/MessageResponse.java

@@ -1,9 +1,11 @@
 package com.coffee.common.config.websocket;
 
-import cn.hutool.core.util.ObjectUtil;
+import cn.hutool.json.JSON;
 import lombok.AllArgsConstructor;
 import lombok.Data;
 
+import java.io.Serializable;
+
 /**
  * @author lifang
  * @version 1.0.0
@@ -13,8 +15,9 @@ import lombok.Data;
  */
 @Data
 @AllArgsConstructor(staticName = "of")
-public class MessageResponse {
+public class MessageResponse implements Serializable {
     private String id;
     private String type;
-    private Object payload;
+    private String param;
+    private JSON payload;
 }

+ 3 - 4
coffee-common/src/main/java/com/coffee/common/config/websocket/MessagingRequest.java

@@ -1,6 +1,7 @@
 package com.coffee.common.config.websocket;
 
 import cn.hutool.core.util.StrUtil;
+import cn.hutool.json.JSONUtil;
 import lombok.Data;
 
 import java.util.*;
@@ -29,8 +30,6 @@ public class MessagingRequest {
 
     private String tenantId;
 
-    private Integer isSys;
-
     public static enum Type{
         sub,unsub
     }
@@ -39,8 +38,8 @@ public class MessagingRequest {
         if(StrUtil.isNullOrUndefined(id)){
             throw new RuntimeException("MessageRequest id不能为空");
         }
-        if(StrUtil.isNullOrUndefined(tenantId)&&isSys==null){
-            throw new RuntimeException("tenantId、isSys不能同时为空");
+        if(StrUtil.isNullOrUndefined(tenantId)){
+            throw new RuntimeException("tenantId不能为空");
         }
     }
 }

+ 51 - 42
coffee-common/src/main/java/com/coffee/common/config/websocket/WebSocketConstant.java

@@ -1,26 +1,41 @@
 package com.coffee.common.config.websocket;
 
 import cn.hutool.core.util.StrUtil;
+import com.coffee.common.config.websocket.handler.TopicWrapper;
 
 /**
  * @author lifang
  * @version 1.0.0
- * @ClassName WebSocketContants.java
+ * @ClassName WebSocketConstants.java
  * @Description websocket订阅所用常量
  * @createTime 2022年03月25日 14:25:00
  */
 public class WebSocketConstant {
+    public static final String MONITOR_TIME_COUNT ="monitor-time-count";
+
+    public static final String MONITOR_STATE_COUNT ="monitor-state-count";
+
+    /**
+     * 病人监控数量订阅
+     */
+    public static final String MONITOR_TOTAL_COUNT ="monitor-total-count";
+
+    public static final String PATIENT_ADD ="patient-add";
+
+    public static final String DEVICE_REPEAT ="device-repeat";
+
+    public static final String DEVICE_NONE ="device-none";
+
 
-    public static final String ALARM_COUNT="alarm-count";
-    public static final String DEVICE_INFO_DETAIL="device-info-detail";
-    public static final String DEVICE_STATE_COUNT="device-state-count";
-    public static final String CLINIC_INFO = "clinic-info";
-    public static final String DEVICE_CONFLICT = "device-conflict";
     /**
      * 病人监控订阅
      */
     public static final String PATIENT_MONITOR="patient-monitor";
 
+    /**
+     * his脚本连接通道
+     */
+    public static final String HIS_CONNECTION ="his-connection";
     /**
      * 主题格式为 device-info-detail:default:45789215623:医院id
      *             alarm-count:default:电量不足:医院id
@@ -29,77 +44,71 @@ public class WebSocketConstant {
      * @param param
      * @return
      */
-    public static String getTopic(String id,String productName,String param,String tenantId){
+    public static TopicWrapper getTopic(String id,String productName,String param,String tenantId){
         productName=StrUtil.isEmptyIfStr(productName)?"default":productName;
         tenantId=StrUtil.isNullOrUndefined(tenantId)?"*":tenantId;
-        return id+"-"+productName+"-"+param+"-"+tenantId;
+        return TopicWrapper.of(id+"-"+productName+"-"+param+"-"+tenantId,param);
     }
 
+
     /**
      * 获取 设备状态变化主题
-     * @param productName
-     * @param param
-     * @param tenantId
+     * @param tenantId 设备所属医院
      * @return
      */
-    public static String getAlarmCount(String productName,String param,String tenantId){
-        return getTopic(ALARM_COUNT,productName,param,tenantId);
+    public static TopicWrapper getMonitorStateCount(String tenantId){
+        return getTopic(MONITOR_STATE_COUNT,null,null,tenantId);
     }
 
     /**
-     * 获取 设备信息变化主题
-     * @param productName
-     * @param param
-     * @param tenantId
+     * 获取 监控总数主题
+     * @param tenantId 设备所属医院
      * @return
      */
-    public static String getDeviceInfoDetailTopic(String productName,String param,String tenantId){
-        return getTopic(DEVICE_INFO_DETAIL,productName,param,tenantId);
+    public static TopicWrapper getMonitorTotalCount(String tenantId){
+        return getTopic(MONITOR_TOTAL_COUNT,null,null,tenantId);
     }
 
-
     /**
-     * 获取 设备状态变化主题
+     * 获取 病人监护变化主题
      * @param productName
      * @param param
      * @param tenantId
      * @return
      */
-    public static String getDeviceStateCount(String productName,String param,String tenantId){
-        return getTopic(DEVICE_STATE_COUNT,productName,param,tenantId);
+    public static TopicWrapper getPatientMonitor(String productName,String param,String tenantId){
+        return getTopic(PATIENT_MONITOR,productName,param,tenantId);
     }
 
-
     /**
-     * 获取 临床信息主题
-     * @param productName
-     * @param param
-     * @param tenantId
+     * 获取 病人新增主题
+     * @param tenantId 设备所属医院
      * @return
      */
-    public static String getClinicInfoTopic(String productName,String param,String tenantId){
-        return getTopic(CLINIC_INFO,productName,param,tenantId);
+    public static TopicWrapper getPatientAdd(String tenantId){
+        return getTopic(PATIENT_ADD,null,null,tenantId);
     }
 
+
     /**
-     * 获取 临床设备冲突主题
-     * @param productName
-     * @param param
+     * 描述: 获取医院临床设备重复数量统计
+     * @author lifang
+     * @date 2022/5/13 9:50
      * @param tenantId
-     * @return
+     * @return TopicWrapper
      */
-    public static String getDeviceConflictTopic(String productName,String param,String tenantId){
-        return getTopic(DEVICE_CONFLICT,productName,param,tenantId);
+    public static TopicWrapper getDeviceRepeat(String tenantId){
+        return getTopic(DEVICE_REPEAT,null,null,tenantId);
     }
 
     /**
-     * 获取 病人监护变化主题
-     * @param productName
-     * @param param
+     * 描述: 获取医院临床设备无绑定数量统计
+     * @author lifang
+     * @date 2022/5/13 9:50
      * @param tenantId
-     * @return
+     * @return TopicWrapper
      */
-    public static String getPatientMonitor(String productName,String param,String tenantId){
-        return getTopic(PATIENT_MONITOR,productName,param,tenantId);
+    public static TopicWrapper getDeviceNone(String tenantId){
+        return getTopic(DEVICE_NONE,null,null,tenantId);
     }
 }

+ 100 - 43
coffee-common/src/main/java/com/coffee/common/config/websocket/handler/Subscribe.java

@@ -1,13 +1,19 @@
 package com.coffee.common.config.websocket.handler;
 
 import cn.hutool.core.collection.CollectionUtil;
+import cn.hutool.core.util.StrUtil;
 import com.coffee.common.Constants;
 import com.coffee.common.bo.LoginUser;
 import com.coffee.common.config.websocket.DefaultMessageListener;
 import com.coffee.common.config.websocket.MessagingRequest;
 import com.coffee.common.config.websocket.WebSocketConstant;
+import com.fasterxml.jackson.databind.ObjectMapper;
+import lombok.extern.slf4j.Slf4j;
+import org.springframework.beans.factory.annotation.Autowired;
 import org.springframework.dao.DataAccessException;
 import org.springframework.data.redis.connection.RedisConnection;
+import org.springframework.data.redis.connection.RedisPubSubCommands;
+import org.springframework.data.redis.connection.Subscription;
 import org.springframework.data.redis.core.RedisCallback;
 import org.springframework.data.redis.core.RedisTemplate;
 import org.springframework.util.ConcurrentReferenceHashMap;
@@ -15,7 +21,10 @@ import org.tio.core.ChannelContext;
 
 import javax.annotation.Resource;
 import java.util.*;
+import java.util.concurrent.CompletableFuture;
 import java.util.concurrent.ConcurrentHashMap;
+import java.util.concurrent.TimeUnit;
+import java.util.concurrent.atomic.AtomicBoolean;
 import java.util.stream.Collectors;
 
 /**
@@ -25,28 +34,36 @@ import java.util.stream.Collectors;
  * @Description TODO
  * @createTime 2022年03月25日 14:18:00
  */
+@Slf4j
 public abstract class Subscribe implements WsHandler {
-    @Resource
+    @Autowired
     private RedisTemplate<String,Object> redisTemplate;
 
+    @Autowired
+    private ObjectMapper objectMapper;
+
     public static final String SUBSCRIBE_TOPIC="subscribe-topic";
     /**
      * 存储主题与ws通道关联
      */
-    private Map<String,Set<ChannelContext>> subscribeTopics=new ConcurrentHashMap<>();
+    private static Map<String,Set<ChannelContext>> subscribeTopics=new ConcurrentHashMap<>();
 
 
     /**
      * 存储主题与redis通道关联
      */
-    private Map<String,RedisConnection> redisConnectionMap=new ConcurrentReferenceHashMap<>();
+    private static Map<String,RedisConnection> redisConnectionMap=new ConcurrentReferenceHashMap<>();
 
 
-    public String getTopic(String productName,String param,String tenantId){
+    public TopicWrapper getTopic(String productName,String param,String tenantId){
         return  WebSocketConstant.getTopic(this.getId(),productName, param, tenantId);
 
     };
 
+    public static Set<ChannelContext> getSubscribeChannel(String topic){
+        return subscribeTopics.get(topic);
+    }
+
 
     @Override
     public void onMessage(MessagingRequest message, ChannelContext channelContext) {
@@ -57,48 +74,76 @@ public abstract class Subscribe implements WsHandler {
         }
         //获取所有设备id
         List<String> params = message.getParams();
-        if(CollectionUtil.isEmpty(params)){
+        if(CollectionUtil.isEmpty(params)&&this.needParam()){
             return;
         }
+        List<TopicWrapper> subScribeTopic =null;
         //需要处理的主题
-        List<String> subScribeTopic =
-                params.stream().map(deviceId -> getTopic(message.getProductName(), deviceId, loginUser.getTenantId()))
-                        .collect(Collectors.toList());
+        if (CollectionUtil.isNotEmpty(params)) {
+            subScribeTopic =
+                    params.stream().map(param -> getTopic(message.getProductName(), param, loginUser.getTenantId()))
+                            .collect(Collectors.toList());
+        }
+        else {
+            subScribeTopic = Collections.singletonList(getTopic(message.getProductName(), null, loginUser.getTenantId()));
+        }
+
         MessagingRequest.Type type = message.getType();
         if(MessagingRequest.Type.sub==type){
             //订阅主题
-            subScribeTopic.forEach(topic->this.subscribe(channelContext,topic));
+            for (TopicWrapper topicWrapper : subScribeTopic) {
+                this.subscribe(channelContext,topicWrapper);
+            }
+//            subScribeTopic.forEach(topicWrapper->this.subscribe(channelContext,topicWrapper));
         }else {
             //取消订阅主题
-            subScribeTopic.forEach(topic->this.unsubscribe(channelContext,topic));
+//            subScribeTopic.forEach(topicWrapper->this.unsubscribe(channelContext,topicWrapper.getTopic()));
         }
+        log.error("订阅成功{}",subScribeTopic.stream().map(TopicWrapper::getTopic).collect(Collectors.toList()));
+
     }
 
     /**
      * ws 订阅主题
      * @param channelContext
-     * @param topic
+     * @param topicWrapper
      */
-    public void subscribe(ChannelContext channelContext, String topic){
+    public void subscribe(ChannelContext channelContext, TopicWrapper topicWrapper){
         //同一主题只订阅一次
-        Set<ChannelContext> channelContexts = Optional.ofNullable(subscribeTopics.get(topic)).orElse(new HashSet<>());
-        if(!subscribeTopics.containsKey(topic)){
-            channelContexts.add(channelContext);
+        Set<ChannelContext> channelContexts = subscribeTopics.computeIfAbsent(topicWrapper.getTopic(), k -> new HashSet<>());
+        channelContexts.add(channelContext);
+        boolean subscribe=false;
+        RedisConnection redisConnection = redisConnectionMap.get(topicWrapper.getTopic());
+        if(redisConnection==null){
+            subscribe=true;
+        }else {
+            Subscription subscription = redisConnection.getSubscription();
+            if(subscription==null||CollectionUtil.isEmpty(subscription.getPatterns())){
+                subscribe=true;
+            }else {
+                Collection<byte[]> patterns = subscription.getPatterns();
+                for (byte[] pattern : patterns) {
+                    String patternName = new String(pattern);
+                    if(topicWrapper.getTopic().equals(patternName)){
+                        subscribe=true;
+                        break;
+                    }
+                }
+            }
+        }
+        if(subscribe){
             redisTemplate.execute(new RedisCallback<Object>() {
                 @Override
                 public Object doInRedis(RedisConnection connection) throws DataAccessException {
-                    connection.pSubscribe(new DefaultMessageListener(getId(),channelContexts),topic.getBytes());
-                    redisConnectionMap.put(topic,connection);
+                    CompletableFuture.runAsync(()->{
+                        connection.pSubscribe(new DefaultMessageListener(getId(),topicWrapper,objectMapper,channelContexts),topicWrapper.getTopic().getBytes());
+                    });
+                    redisConnectionMap.put(topicWrapper.getTopic(),connection);
                     return null;
                 }
             });
         }
-        subscribeTopics.put(topic,channelContexts);
-        //将主题与ws通道绑定
-        Object result = Optional.ofNullable(channelContext.get(SUBSCRIBE_TOPIC)).orElse(new HashSet<>());
-        Set<String> subscribeTopicSet= (Set<String>) result;
-        subscribeTopicSet.add(topic);
-        channelContext.set(SUBSCRIBE_TOPIC,subscribeTopicSet);
+        getTopicByChannel(channelContext).add(topicWrapper.getTopic());
     };
 
     /**
@@ -107,28 +152,40 @@ public abstract class Subscribe implements WsHandler {
      * @param topic
      */
     public void unsubscribe(ChannelContext channelContext, String topic){
-        if(subscribeTopics.containsKey(topic)){
-            Set<ChannelContext> channelContexts = subscribeTopics.get(topic);
-            if(CollectionUtil.isNotEmpty(channelContexts)){
-                channelContexts.remove(channelContext);
-            }
-            //重新获取集合,避免多线程发生冲突,再次判断此时是否为空
-            if(CollectionUtil.isEmpty(subscribeTopics.get(topic))){
-                subscribeTopics.remove(topic);
-                redisTemplate.execute(new RedisCallback<Object>() {
-                    @Override
-                    public Object doInRedis(RedisConnection connection) throws DataAccessException {
-                        RedisConnection redisConnection = redisConnectionMap.get(topic);
-                        if (redisConnection!=null) {
-                            redisConnection.getSubscription().unsubscribe(topic.getBytes());
-                        }
-                        return null;
-                    }
-                });
-                redisConnectionMap.remove(topic);
-            }
+        if(StrUtil.isEmpty(topic)){
+            return;
         }
+        AtomicBoolean remove = new AtomicBoolean(false);
+        subscribeTopics.computeIfPresent(topic,(k,v)->{
+            v.remove(channelContext);
+//            if(CollectionUtil.isEmpty(v)){
+                remove.set(true);
+//                redisTemplate.execute(new RedisCallback<Object>() {
+//                    @Override
+//                    public Object doInRedis(RedisConnection connection) throws DataAccessException {
+//                        RedisConnection redisConnection = redisConnectionMap.get(topic);
+//                        if (redisConnection!=null) {
+//                            Optional.ofNullable(redisConnection.getSubscription())
+//                                    .map(subscription -> {
+//                                        subscription.pUnsubscribe(topic.getBytes());
+//                                        return subscription;
+//                                    });
+//                        }
+//                        return null;
+//                    }
+//                });
+//                redisConnectionMap.remove(topic);
+//            }
+            return v;
+        });
     };
 
 
+    public Set<String> getTopicByChannel(ChannelContext channelContext){
+        Object result = Optional.ofNullable(channelContext.get(SUBSCRIBE_TOPIC)).orElse(new HashSet<>());
+        channelContext.set(SUBSCRIBE_TOPIC,result);
+        return  (Set<String>) result;
+    }
+
+
 }

+ 24 - 0
coffee-common/src/main/java/com/coffee/common/config/websocket/handler/TopicWrapper.java

@@ -0,0 +1,24 @@
+package com.coffee.common.config.websocket.handler;
+
+import lombok.AllArgsConstructor;
+import lombok.Data;
+
+/**
+ * @author lifang
+ * @version 1.0.0
+ * @ClassName Topic.java
+ * @Description ws订阅主题
+ * @createTime 2022年05月07日 17:14:00
+ */
+@Data
+@AllArgsConstructor(staticName = "of")
+public class TopicWrapper {
+    /**
+     * 主题
+     */
+    private String topic;
+    /**
+     * 订阅参数
+     */
+    private String param;
+}

+ 9 - 0
coffee-common/src/main/java/com/coffee/common/config/websocket/handler/WsHandler.java

@@ -16,4 +16,13 @@ public interface WsHandler {
     void onMessage(MessagingRequest message, ChannelContext channelContext);
 
     void close(ChannelContext channelContext);
+
+    /**
+     * 描述: 参数是否为必输的
+     * @author lifang
+     * @date 2022/5/9 11:20
+     * @param
+     * @return boolean
+     */
+    boolean needParam();
 }

+ 19 - 3
coffee-common/src/main/java/com/coffee/common/crud/BaseService.java

@@ -27,6 +27,7 @@ import com.coffee.common.exception.CustomException;
 import org.apache.ibatis.binding.MapperMethod;
 import org.springframework.data.domain.PageRequest;
 import org.springframework.jdbc.BadSqlGrammarException;
+import org.springframework.transaction.annotation.Transactional;
 
 import java.io.Serializable;
 import java.sql.SQLSyntaxErrorException;
@@ -63,6 +64,7 @@ public abstract class BaseService<M extends BaseMapper<E>, E,PK extends Serializ
     }
 
     @Override
+    @Transactional(rollbackFor = Exception.class)
     public boolean saveBatch(Collection<E> entityList, int batchSize) {
         entityList.forEach(this::validateBeforeSave);
         if (super.saveBatch(entityList, batchSize)) {
@@ -72,6 +74,16 @@ public abstract class BaseService<M extends BaseMapper<E>, E,PK extends Serializ
         return false;
     }
 
+    @Override
+    @Transactional(rollbackFor = Exception.class)
+    public boolean save(E entity) {
+        if (super.save(entity)) {
+            postSave(entity);
+            return true;
+        }
+        return false;
+    }
+
     /**
      * @Author lifang
      * @Date 10:05 2022/3/14
@@ -82,6 +94,7 @@ public abstract class BaseService<M extends BaseMapper<E>, E,PK extends Serializ
 
     @Override
     @Deprecated
+    @Transactional(rollbackFor = Exception.class)
     public boolean saveOrUpdate(E entity) {
         if (null != entity) {
             TableInfo tableInfo = TableInfoHelper.getTableInfo(this.entityClass);
@@ -114,6 +127,7 @@ public abstract class BaseService<M extends BaseMapper<E>, E,PK extends Serializ
      * @return boolean
      **/
     @Override
+    @Transactional(rollbackFor = Exception.class)
     @Deprecated
     public boolean saveOrUpdateBatch(Collection<E> entityList, int batchSize) {
         TableInfo tableInfo = TableInfoHelper.getTableInfo(entityClass);
@@ -187,6 +201,7 @@ public abstract class BaseService<M extends BaseMapper<E>, E,PK extends Serializ
     }
 
     @Override
+    @Transactional(rollbackFor = Exception.class)
     public boolean updateById(E entity) {
         validateBeforeUpdate(entity);
         if (super.updateById(entity)) {
@@ -197,6 +212,7 @@ public abstract class BaseService<M extends BaseMapper<E>, E,PK extends Serializ
     }
 
     @Override
+    @Transactional(rollbackFor = Exception.class)
     public boolean updateBatchById(Collection<E> entityList) {
         entityList.forEach(this::validateBeforeUpdate);
         if (super.updateBatchById(entityList)) {
@@ -257,9 +273,9 @@ public abstract class BaseService<M extends BaseMapper<E>, E,PK extends Serializ
                 }
             });
         }
-//        else {
-//            queryWrapper.orderByDesc("create_time");
-//        }
+        else {
+            queryWrapper.orderByDesc("create_time");
+        }
         if(StrUtil.isNotEmpty(param.getTenantId())&&!StrUtil.isNullOrUndefined(param.getTenantId())){
             LoginUser loginUser = (LoginUser) StpUtil.getTokenSession().get(com.coffee.common.Constants.LOGIN_USER_KEY);
             //是否为系统用户

+ 5 - 3
coffee-common/src/main/java/com/coffee/common/crud/controller/BaseSaveController.java

@@ -2,8 +2,10 @@ package com.coffee.common.crud.controller;
 
 import com.baomidou.mybatisplus.core.mapper.Mapper;
 import com.coffee.common.crud.BaseService;
+import com.coffee.common.entity.GenericEntity;
 import com.coffee.common.result.R;
 import io.swagger.annotations.ApiOperation;
+import org.springframework.validation.annotation.Validated;
 import org.springframework.web.bind.annotation.*;
 
 import java.io.Serializable;
@@ -26,14 +28,14 @@ public interface BaseSaveController<E,K extends Serializable> extends
 
     @PostMapping("/_batch")
     @ApiOperation(value = "批量新增数据")
-    default R add(@RequestBody List<E> payload) {
+    default R add(@RequestBody @Validated(GenericEntity.Insert.class) List<E> payload) {
         saveAuth();
         return getService().saveBatch(payload)?R.success():R.fail("数据新增失败");
     }
 
     @PostMapping("/add")
     @ApiOperation(value = "新增单个数据,并返回新增后的数据.")
-    default R add(@RequestBody E payload) {
+    default R add(@RequestBody @Validated(GenericEntity.Insert.class)E payload) {
         saveAuth();
         return getService().save(payload)?R.success(payload):R.fail("数据新增失败");
     }
@@ -41,7 +43,7 @@ public interface BaseSaveController<E,K extends Serializable> extends
 
     @PostMapping("/edit")
     @ApiOperation(value = "根据ID修改数据")
-    default R update(@RequestBody E payload) {
+    default R update(@RequestBody @Validated(GenericEntity.Update.class)E payload) {
         editAuth();
         return getService().updateById(payload)?R.success(payload):R.fail("更新失败");
     }

+ 9 - 0
coffee-common/src/main/java/com/coffee/common/entity/GenericEntity.java

@@ -4,6 +4,7 @@ import com.baomidou.mybatisplus.annotation.FieldFill;
 import com.baomidou.mybatisplus.annotation.IdType;
 import com.baomidou.mybatisplus.annotation.TableField;
 import com.baomidou.mybatisplus.annotation.TableId;
+import com.fasterxml.jackson.annotation.JsonIgnore;
 import com.fasterxml.jackson.annotation.JsonIgnoreProperties;
 import com.fasterxml.jackson.databind.annotation.JsonSerialize;
 import com.fasterxml.jackson.databind.ser.std.ToStringSerializer;
@@ -22,6 +23,7 @@ public abstract class  GenericEntity<PK> implements Entity,RecordModifierEntity,
     @TableId(type = IdType.ASSIGN_ID)
     @ApiModelProperty(value = "id")
     @JsonSerialize(using = ToStringSerializer.class)
+    @NotNull(groups = Update.class,message = "id不可为空")
     private PK id;
 
     @TableField(fill = FieldFill.INSERT)
@@ -35,4 +37,11 @@ public abstract class  GenericEntity<PK> implements Entity,RecordModifierEntity,
 
     @TableField(fill = FieldFill.INSERT_UPDATE)
     private Date updateTime;
+
+    /* 分组校验 */
+    public @interface Update {
+    }
+
+    public @interface Insert {
+    }
 }

+ 7 - 5
coffee-common/src/main/java/com/coffee/common/redis/RedisConfig.java

@@ -6,6 +6,7 @@ import com.fasterxml.jackson.annotation.JsonTypeInfo;
 import com.fasterxml.jackson.annotation.PropertyAccessor;
 import com.fasterxml.jackson.databind.ObjectMapper;
 import com.fasterxml.jackson.databind.jsontype.impl.LaissezFaireSubTypeValidator;
+import lombok.AllArgsConstructor;
 import lombok.extern.slf4j.Slf4j;
 import org.springframework.cache.annotation.CachingConfigurerSupport;
 import org.springframework.cache.annotation.EnableCaching;
@@ -24,8 +25,10 @@ import org.springframework.data.redis.serializer.StringRedisSerializer;
 @Configuration
 @EnableCaching
 @Slf4j
+@AllArgsConstructor
 public class RedisConfig extends CachingConfigurerSupport {
 
+    private final ObjectMapper objectMapper;
     @Bean
     public RedisTemplate<String, Object> redisTemplate(RedisConnectionFactory connectionFactory) {
         RedisTemplate<String, Object> redisTemplate = new RedisTemplate<>();
@@ -34,15 +37,14 @@ public class RedisConfig extends CachingConfigurerSupport {
         Jackson2JsonRedisSerializer jackson2JsonRedisSerializer = new Jackson2JsonRedisSerializer(Object.class);
 
 
-        ObjectMapper objectMapper = new ObjectMapper();
-        objectMapper.setVisibility(PropertyAccessor.ALL, JsonAutoDetect.Visibility.ANY);
-        objectMapper.activateDefaultTyping(LaissezFaireSubTypeValidator.instance, ObjectMapper.DefaultTyping.NON_FINAL, JsonTypeInfo.As.WRAPPER_ARRAY);
+//        ObjectMapper objectMapper = new ObjectMapper();
+//        objectMapper.setVisibility(PropertyAccessor.ALL, JsonAutoDetect.Visibility.ANY);
+//        objectMapper.activateDefaultTyping(LaissezFaireSubTypeValidator.instance, ObjectMapper.DefaultTyping.NON_FINAL, JsonTypeInfo.As.WRAPPER_ARRAY);
 
         jackson2JsonRedisSerializer.setObjectMapper(objectMapper);
 
-        FastJsonRedisSerializer<Object> fastJsonRedisSerializer = new FastJsonRedisSerializer<>(Object.class);
         // 设置value的序列化规则和 key的序列化规则
-        redisTemplate.setValueSerializer(fastJsonRedisSerializer);
+        redisTemplate.setValueSerializer(jackson2JsonRedisSerializer);
         redisTemplate.setKeySerializer(new StringRedisSerializer());
 
         redisTemplate.setHashKeySerializer(jackson2JsonRedisSerializer);

+ 36 - 1
coffee-framework/src/main/java/com/coffee/framework/config/WebAppMvcConfig.java

@@ -1,14 +1,24 @@
 package com.coffee.framework.config;
 
 import cn.hutool.core.collection.CollectionUtil;
+import cn.hutool.core.util.StrUtil;
 import com.coffee.common.config.BooleanToIntegerSerializer;
+import com.fasterxml.jackson.core.JsonParser;
+import com.fasterxml.jackson.core.JsonProcessingException;
+import com.fasterxml.jackson.databind.DeserializationContext;
 import com.fasterxml.jackson.databind.DeserializationFeature;
 import com.fasterxml.jackson.databind.ObjectMapper;
+import com.fasterxml.jackson.databind.deser.std.StdScalarDeserializer;
+import com.fasterxml.jackson.databind.deser.std.StringDeserializer;
 import com.fasterxml.jackson.databind.module.SimpleModule;
+import com.fasterxml.jackson.databind.ser.std.StringSerializer;
 import com.fasterxml.jackson.databind.ser.std.ToStringSerializer;
+import org.python.antlr.ast.Str;
 import org.springframework.beans.factory.annotation.Autowired;
 import org.springframework.context.annotation.Configuration;
 import org.springframework.context.annotation.Profile;
+import org.springframework.format.Formatter;
+import org.springframework.format.FormatterRegistry;
 import org.springframework.http.converter.HttpMessageConverter;
 import org.springframework.http.converter.json.MappingJackson2HttpMessageConverter;
 import org.springframework.web.servlet.HandlerInterceptor;
@@ -16,6 +26,8 @@ import org.springframework.web.servlet.config.annotation.InterceptorRegistry;
 import org.springframework.web.servlet.config.annotation.ResourceHandlerRegistry;
 import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;
 
+import java.io.IOException;
+import java.text.ParseException;
 import java.text.SimpleDateFormat;
 import java.util.*;
  
@@ -41,6 +53,17 @@ public class WebAppMvcConfig implements WebMvcConfigurer {
         SimpleModule booleanSimpleModule = new SimpleModule();
         booleanSimpleModule.addSerializer(Boolean.class, new BooleanToIntegerSerializer());
         booleanSimpleModule.addSerializer(Boolean.TYPE, new BooleanToIntegerSerializer());
+
+        SimpleModule stringModule = new SimpleModule();
+        stringModule.addSerializer(String.class,new StringSerializer());
+        stringModule.addDeserializer(String.class, new StdScalarDeserializer<String>(String.class) {
+            @Override
+            public String deserialize(JsonParser p, DeserializationContext ctxt) throws IOException, JsonProcessingException {
+                String text = p.getText();
+                return StrUtil.isBlankIfStr(text)?null:text;
+            }
+        });
+        objectMapper.registerModule(stringModule);
         objectMapper.registerModule(booleanSimpleModule);
         // 设置格式化内容
         converter.setObjectMapper(objectMapper);
@@ -74,6 +97,18 @@ public class WebAppMvcConfig implements WebMvcConfigurer {
     }
 
 
+    @Override
+    public void addFormatters(FormatterRegistry registry) {
+        registry.addFormatterForFieldType(String.class, new Formatter<String>() {
+            @Override
+            public String parse(String text, Locale locale) throws ParseException {
+                return StrUtil.isBlankIfStr(text)?null:text;
+            }
 
-
+            @Override
+            public String print(String object, Locale locale) {
+                return object;
+            }
+        });
+    }
 }

+ 2 - 5
coffee-system/src/main/java/com/coffee/aliyun/AliyunConsumerGroupService.java

@@ -8,15 +8,12 @@ import com.coffee.aliyun.utils.EnumUtils;
 import com.coffee.aliyun.utils.Items;
 import com.coffee.bus.bean.AliIotConfig;
 import com.coffee.bus.entity.BusDeviceEntity;
-import com.coffee.bus.entity.BusDeviceHistoryEntity;
 import com.coffee.bus.entity.BusDeviceRunningEntity;
-import com.coffee.bus.entity.BusInfusionHistoryEntity;
 import com.coffee.bus.listener.event.bean.DeviceInfoEvent;
 import com.coffee.bus.service.LocalBusDeviceHistoryService;
 import com.coffee.bus.service.LocalBusDeviceService;
 import com.coffee.bus.service.LocalBusInfusionHistoryService;
 import lombok.extern.slf4j.Slf4j;
-import org.springframework.beans.BeanUtils;
 import org.springframework.beans.factory.annotation.Autowired;
 import org.springframework.beans.factory.annotation.Value;
 import org.springframework.context.annotation.Lazy;
@@ -145,7 +142,7 @@ public class AliyunConsumerGroupService {
                     log.info(deviceName+"设备未激活");
                 }
                 // 更新设备状态
-                deviceService.updateByDeviceId(device);
+                deviceService.updateDevice(device);
             }else if (topic.matches("[\\w\\/]*event/property/post$")){//设备属性上报
                 // 设备属性集合
                 Items items = new Items(content.getJSONObject("items"));
@@ -186,7 +183,7 @@ public class AliyunConsumerGroupService {
 
                     // 设置配置信息
                     device.setConfig(config);
-                    deviceService.saveByDeviceId(device);
+                    deviceService.saveDevice(device);
                 }else if ("delete".equals(action)){
                     // 删除设备
                     deviceService.removeByDeviceId(deviceName);

+ 3 - 0
coffee-system/src/main/java/com/coffee/aliyun/AliyunIotSubscribeClient.java

@@ -9,6 +9,7 @@ import org.apache.qpid.jms.JmsConnectionListener;
 import org.apache.qpid.jms.message.JmsInboundMessageDispatch;
 import org.springframework.boot.context.properties.EnableConfigurationProperties;
 import org.springframework.context.annotation.Configuration;
+import org.springframework.scheduling.annotation.Async;
 import org.springframework.stereotype.Component;
 
 import javax.crypto.Mac;
@@ -85,6 +86,8 @@ public class AliyunIotSubscribeClient {
 
     @Getter
     private List<Connection> connections = null;
+
+    @Async
     public void start(MessageListener messageListener) throws Exception {
         // 先关闭一下
         close();

+ 14 - 13
coffee-system/src/main/java/com/coffee/bus/controller/BusAlarmController.java

@@ -2,19 +2,19 @@ package com.coffee.bus.controller;
 
 import cn.dev33.satoken.annotation.SaCheckPermission;
 import com.baomidou.mybatisplus.core.mapper.Mapper;
+import com.baomidou.mybatisplus.core.metadata.IPage;
+import com.coffee.bus.service.dto.AlarmQuery;
+import com.coffee.bus.entity.BusClinicEntity;
 import com.coffee.bus.entity.BusDeviceAlarmEntity;
-import com.coffee.bus.enums.DeviceTypeEnum;
 import com.coffee.bus.service.LocalBusDeviceAlarmService;
 import com.coffee.common.crud.BaseService;
 import com.coffee.common.crud.controller.BaseCrudController;
 import com.coffee.common.result.R;
 import io.swagger.annotations.*;
 import lombok.AllArgsConstructor;
-import org.springframework.util.ReflectionUtils;
+import org.springframework.validation.annotation.Validated;
 import org.springframework.web.bind.annotation.*;
 
-import java.lang.reflect.Field;
-
 /**
  * @author lifang
  * @version 1.0.0
@@ -42,19 +42,20 @@ public class BusAlarmController extends BaseCrudController<BusDeviceAlarmEntity,
         return R.success();
     }
 
+
+    @PostMapping("/query/page")
+    @SaCheckPermission("bus:alarm:query")
+    @ApiOperation(value = "分页(输注查询)查询",notes = "权限:【bus:alarm:query】")
+    public R<IPage<BusDeviceAlarmEntity>> page(@RequestBody@Validated AlarmQuery query){
+        return R.success(deviceAlarmService.pageQuery(query));
+    }
     @Override
     public BaseService<? extends Mapper<BusDeviceAlarmEntity>, BusDeviceAlarmEntity, String> getService() {
         return deviceAlarmService;
     }
 
-    public static void main(String[] args) {
-        set(DeviceTypeEnum.continuous);
-    }
-
-
-    public static  void set(Object value){
-        Field ordinal = ReflectionUtils.findField(value.getClass(), "ordinal");
-        ordinal.setAccessible(true);
-        System.out.println( ReflectionUtils.getField(ordinal,value));
+    @Override
+    public String getPermissionPrefix() {
+        return "bus:alarm";
     }
 }

+ 92 - 21
coffee-system/src/main/java/com/coffee/bus/controller/BusClinicController.java

@@ -1,17 +1,25 @@
 package com.coffee.bus.controller;
 
-import com.baomidou.mybatisplus.core.mapper.Mapper;
+import cn.dev33.satoken.annotation.SaCheckPermission;
+import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
+import com.baomidou.mybatisplus.core.metadata.IPage;
 import com.coffee.bus.controller.vo.ClinicStatsVo;
-import com.coffee.bus.entity.BusClinicEntity;
-import com.coffee.bus.service.LocalBusClinicService;
-import com.coffee.bus.service.dto.ClinicStatsReturnResult;
-import com.coffee.common.crud.BaseService;
-import com.coffee.common.crud.controller.BaseCrudController;
+import com.coffee.bus.entity.*;
+import com.coffee.bus.registry.device.DeviceRegistry;
+import com.coffee.bus.service.*;
+import com.coffee.bus.service.dto.*;
+import com.coffee.common.exception.CustomException;
 import com.coffee.common.result.R;
 import io.swagger.annotations.Api;
 import io.swagger.annotations.ApiOperation;
 import lombok.AllArgsConstructor;
+import org.springframework.validation.annotation.Validated;
 import org.springframework.web.bind.annotation.*;
+import java.util.List;
+import java.util.Map;
+import java.util.concurrent.CompletableFuture;
+import java.util.stream.Collectors;
+
 /**
  * @author lifang
  * @version 1.0.0
@@ -23,26 +31,89 @@ import org.springframework.web.bind.annotation.*;
 @AllArgsConstructor
 @RequestMapping("/bus/clinic")
 @Api(tags = "病人临床手术管理",description = "统一权限前缀(bus:clinic),例如新增bus:clinic:add")
-public class BusClinicController extends BaseCrudController<BusClinicEntity, String> {
+public class BusClinicController {
     private final LocalBusClinicService clinicService;
-
-
+    private final LocalBusEvaluationService evaluationService;
+    private final LocalBusInfusionHistoryService infusionHistoryService;
+    private final LocalBusInfusionModifyService infusionModifyService;
+    private final LocalBusDeviceHistoryService deviceHistoryService;
+    private final DeviceRegistry deviceRegistry;
     @PostMapping("/stats")
-    @ApiOperation("临床过程中的数据记录")
-    public R<ClinicStatsReturnResult> list(@RequestBody ClinicStatsVo statsVo) {
+    @ApiOperation(value = "临床过程中的数据记录",notes = "权限【无】")
+    public R<ClinicStatsReturnResult> stats(@RequestBody ClinicStatsVo statsVo) {
         return R.success(clinicService.stats(statsVo));
     }
-    /**
-     * 权限控制前缀
-     * @return
-     */
-    @Override
-    public String getPermissionPrefix() {
-        return "bus:clinic";
+
+
+    @PostMapping("/page")
+    @SaCheckPermission("bus:clinic:query")
+    @ApiOperation(value = "临床管理分页查询",notes = "权限【bus:clinic:query】")
+    public R<IPage<ClinicResult>> page(@RequestBody@Validated ClinicQuery query) {
+        return R.success(clinicService.pageQuery(query));
     }
 
-    @Override
-    public BaseService<? extends Mapper<BusClinicEntity>, BusClinicEntity, String> getService() {
-        return clinicService;
+
+    @PostMapping("/anal/record/{clinicId}")
+    @SaCheckPermission("bus:clinic:query")
+    @ApiOperation(value = "查询临床信息的镇痛访视记录单",notes = "权限【bus:clinic:query】")
+    public R<ClinicAnalRecordResult> analRecord(@PathVariable("clinicId") String clinicId){
+        ClinicAnalRecordResult result = new ClinicAnalRecordResult();
+        BusClinicEntity clinic = clinicService.getById(clinicId);
+        if(clinic==null){
+            throw new CustomException("该临床信息不存在");
+        }
+        //填充临床信息
+        result.setClinic(ClinicAnalClinicRecord.parse(clinic));
+        CompletableFuture
+                .runAsync(()->{
+                    //填充评价记录
+                    result.setEvaluations(evaluationService.list(new QueryWrapper<BusEvaluationEntity>().lambda().eq(BusEvaluationEntity::getClinicId,clinicId).orderByAsc(BusEvaluationEntity::getEvaluateTime)));
+                })
+                .thenAcceptAsync(ignore->{
+                    //填充输注记录
+                    List<BusInfusionHistoryEntity> infusionHistories = infusionHistoryService.list(new QueryWrapper<BusInfusionHistoryEntity>().lambda()
+                            .eq(BusInfusionHistoryEntity::getClinicId, clinicId)
+                            .orderByAsc(BusInfusionHistoryEntity::getStartTime));
+
+                    //添加设备别名
+                    Map<String, List<BusInfusionHistoryEntity>> infusionByDeviceId = infusionHistories.stream().collect(Collectors.groupingBy(BusInfusionHistoryEntity::getDeviceId));
+                    infusionByDeviceId.forEach((deviceId,infusions)->{
+                        String alias = deviceRegistry.getOperator(deviceId).getAlias();
+                        infusions.forEach(infusion->infusion.setAlias(alias));
+                    });
+
+                    result.fillUndoInfo(infusionHistories);
+
+
+                    List<String> infusionIds = infusionHistories.stream().map(BusInfusionHistoryEntity::getId).collect(Collectors.toList());
+                    List<BusInfusionModifyEntity> infusionModifies = infusionModifyService.list(new QueryWrapper<BusInfusionModifyEntity>().lambda()
+                            .in(BusInfusionModifyEntity::getInfusionId, infusionIds));
+                    result.fillInfusionRecords(infusionHistories,infusionModifies);
+                })
+                .thenAccept(ignore->{
+                    List<String> infusionIds = result.getInfusionRecords().stream().map(ClinicAnalInfusionRecord::getId).collect(Collectors.toList());
+                    List<BusDeviceHistoryEntity> deviceHistories = deviceHistoryService.list(new QueryWrapper<BusDeviceHistoryEntity>()
+                            .lambda()
+                            .select(BusDeviceHistoryEntity::getInfusionId,BusDeviceHistoryEntity::getPcaValidCount,BusDeviceHistoryEntity::getInfusionModifyId,
+                                    BusDeviceHistoryEntity::getPcaInvalidCount,BusDeviceHistoryEntity::getInputDose,BusDeviceHistoryEntity::getUploadTime)
+                            .in(BusDeviceHistoryEntity::getInfusionId, infusionIds)
+                            .eq(BusDeviceHistoryEntity::getMaster, true));
+                    //标记输注
+                    result.markInfusion(deviceHistories);
+                    List<ClinicStatsQueryResult> statsQueryResults = deviceHistories.stream().map(history -> {
+                        ClinicStatsQueryResult statsQueryResult = new ClinicStatsQueryResult();
+                        statsQueryResult.setInputDose(history.getInputDose());
+                        statsQueryResult.setInValidCount(history.getPcaInvalidCount());
+                        statsQueryResult.setValidCount(history.getPcaValidCount());
+                        statsQueryResult.setUploadTime(history.getUploadTime());
+                        return statsQueryResult;
+                    }).collect(Collectors.toList());
+                    //填充统计信息
+                    result.setStats(ClinicStatsReturnResult.of(statsQueryResults));
+                })
+                .join();
+
+
+        return R.success(result);
     }
 }

+ 0 - 19
coffee-system/src/main/java/com/coffee/bus/controller/BusConstantController.java

@@ -34,25 +34,6 @@ public class BusConstantController {
     private HashMap<ConstantEnum, AbstractConstantService> constantHashMap=new HashMap<>();
 
 
-    @ApiOperation("该接口仅用来展示 常量-医生 的数据接口,无任何实际意义")
-    @PostMapping("/doctor")
-    private R doctor(@RequestBody BusConDoctor doctor){
-        return R.success();
-    }
-
-    @ApiOperation("该接口仅用来展示 常量-混合 的数据接口,无任何实际意义")
-    @PostMapping("/mix")
-    private R mix(@RequestBody BusConMixEntity doctor){
-        return R.success();
-    }
-
-
-    @ApiOperation("该接口仅用来展示 常量-报警 的数据接口,无任何实际意义")
-    @PostMapping("/alarm")
-    private R alarm(@RequestBody BusConAlarmEntity doctor){
-        return R.success();
-    }
-
     @Autowired
     public BusConstantController(List<AbstractConstantService> constantList) {
         constantList.stream().collect(Collectors.groupingBy(AbstractConstantService::getName)).forEach((k, vs)->{

+ 104 - 5
coffee-system/src/main/java/com/coffee/bus/controller/BusDeviceController.java

@@ -1,14 +1,41 @@
 package com.coffee.bus.controller;
 
+import cn.dev33.satoken.annotation.SaCheckPermission;
+import cn.hutool.core.collection.CollectionUtil;
+import cn.hutool.core.util.ObjectUtil;
+import cn.hutool.core.util.StrUtil;
 import com.baomidou.mybatisplus.core.mapper.Mapper;
+import com.baomidou.mybatisplus.core.metadata.IPage;
+import com.coffee.bus.controller.vo.DeviceBindVo;
 import com.coffee.bus.entity.BusDeviceEntity;
+import com.coffee.bus.entity.BusDeviceRunningEntity;
+import com.coffee.bus.enums.DeviceAlarmEnum;
+import com.coffee.bus.enums.DeviceStatusEnum;
+import com.coffee.bus.exception.BusinessException;
+import com.coffee.bus.exception.ErrorStatus;
+import com.coffee.bus.service.LocalBusDeviceRunningService;
 import com.coffee.bus.service.LocalBusDeviceService;
+import com.coffee.bus.service.dto.DeviceQuery;
+import com.coffee.bus.service.dto.DeviceResult;
 import com.coffee.common.crud.BaseService;
 import com.coffee.common.crud.controller.BaseCrudController;
+import com.coffee.common.exception.CustomException;
+import com.coffee.common.result.R;
 import io.swagger.annotations.Api;
+import io.swagger.annotations.ApiOperation;
+import io.swagger.annotations.ApiParam;
 import lombok.AllArgsConstructor;
-import org.springframework.web.bind.annotation.RequestMapping;
-import org.springframework.web.bind.annotation.RestController;
+import lombok.extern.slf4j.Slf4j;
+import org.springframework.web.bind.annotation.*;
+import org.springframework.web.context.request.async.DeferredResult;
+
+import java.util.List;
+import java.util.Objects;
+import java.util.concurrent.CompletableFuture;
+import java.util.concurrent.FutureTask;
+import java.util.concurrent.locks.Lock;
+import java.util.concurrent.locks.ReentrantLock;
+import java.util.stream.Collectors;
 
 /**
  * @author lifang
@@ -16,15 +43,32 @@ import org.springframework.web.bind.annotation.RestController;
  * @ClassName BusHospitalController.java
  * @Description TODO
  * @createTime 2022年03月19日 09:28:00
+ * @accendant 龙三郎
  */
+@Slf4j
 @RestController
 @AllArgsConstructor
 @RequestMapping("/bus/device/info")
 @Api(tags = "设备管理",description = "统一权限前缀(device:info),device:info:add")
 public class BusDeviceController extends BaseCrudController<BusDeviceEntity, String> {
-    private final LocalBusDeviceService deviceRegisteredService;
-
+    private final LocalBusDeviceService deviceService;
+    private final LocalBusDeviceRunningService runningService;
+    @PostMapping("/shift/bind")
+    @ApiOperation(value = "设备换绑",notes = "权限【device:info:shift】")
+    public R shift(@RequestBody DeviceBindVo vo){
+        if(StrUtil.isEmpty(vo.getBindTenantId())|| CollectionUtil.isEmpty(vo.getDeviceIds())){
+            throw new CustomException("选择的医院、设备不能为空");
+        }
+        deviceService.shift(vo.getDeviceIds(),vo.getBindTenantId());
+        return R.success(DeviceAlarmEnum.values());
+    }
 
+    @PostMapping("/query/page")
+    @SaCheckPermission("device:info:query")
+    @ApiOperation(value = "设备管理分页查询",notes = "权限【device:info:query】")
+    public R<IPage<DeviceResult>> pageQuery(@RequestBody DeviceQuery query){
+        return R.success(deviceService.pageQuery(query.getPage(),query));
+   }
     /**
      * 权限控制前缀
      * @return
@@ -37,6 +81,61 @@ public class BusDeviceController extends BaseCrudController<BusDeviceEntity, Str
 
     @Override
     public BaseService<? extends Mapper<BusDeviceEntity>, BusDeviceEntity, String> getService() {
-        return deviceRegisteredService;
+        return deviceService;
+    }
+
+    /**
+     * @author 龙三郎
+     * 新增设备,只有超级管理员才有此权限,如果该设备在系统中存在,则更新,如果设备在系统中不存在,在阿里云平台存在,则从阿里云获取后插入。
+     * @param payload
+     * @return
+     */
+    @Override
+    @PostMapping("/add")
+    @ApiOperation(value = "新增单个数据,并返回新增后的数据.")
+    public R<BusDeviceEntity> add(BusDeviceEntity payload) {
+        log.info("添加设备");
+        // 设备id不能为空
+        if (StrUtil.isEmpty(payload.getDeviceId())){
+            throw new BusinessException(ErrorStatus.DEVICEID_IS_EMPTY);
+        }
+        // 根据deviceId从阿里云获取设备信息。
+        BusDeviceEntity device = deviceService.addDevice(payload.getDeviceId());
+        if (ObjectUtil.isNull(device)){
+            return R.fail("设备添加失败");
+        }
+        return R.success(device);
+    }
+
+    /**
+     * @author 龙三郎
+     * 从阿里云同步系统所有的设备,只有超级管理员才有此权限。将阿里云所有的设备同步到系统。
+     * @return
+     */
+    @ApiOperation(value = "从阿里云同步设备",notes = "从阿里云平台获取设备并更新")
+    @PutMapping("/sync-device")
+    public R syncDevice() {
+        int i = deviceService.syncAllDevice();
+        if (i > 0){
+            return R.success(i,"同步成功");
+        }else {
+            return R.fail("同步失败");
+        }
+    }
+
+    /**
+     * @author 龙三郎
+     * 从阿里云更新系统中存在的设备,如果设备在系统中不存在,则不更新。
+     * @return
+     */
+    @ApiOperation(value = "从阿里云更新本地设备",notes = "从阿里云平台获取设备并更新,参数为设备id列表,格式如['123456','456123'],参数可为空。")
+    @PutMapping("/sync-device/batch")
+    public R syncDevice(@RequestBody List<String> ids) {
+        int i = deviceService.syncDevice(ids);
+        if (i > 0){
+            return R.success(i,"同步成功");
+        }else {
+            return R.fail("同步失败");
+        }
     }
 }

+ 17 - 0
coffee-system/src/main/java/com/coffee/bus/controller/BusDeviceHistoryController.java

@@ -1,12 +1,22 @@
 package com.coffee.bus.controller;
 
+import cn.dev33.satoken.annotation.SaCheckPermission;
 import com.baomidou.mybatisplus.core.mapper.Mapper;
+import com.baomidou.mybatisplus.core.metadata.IPage;
+import com.coffee.bus.entity.BusDeviceAlarmEntity;
 import com.coffee.bus.entity.BusDeviceHistoryEntity;
 import com.coffee.bus.service.LocalBusDeviceHistoryService;
+import com.coffee.bus.service.dto.AlarmQuery;
+import com.coffee.bus.service.dto.DeviceHistoryQuery;
 import com.coffee.common.crud.BaseService;
 import com.coffee.common.crud.controller.BaseCrudController;
+import com.coffee.common.result.R;
 import io.swagger.annotations.Api;
+import io.swagger.annotations.ApiOperation;
 import lombok.AllArgsConstructor;
+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;
 
@@ -33,6 +43,13 @@ public class BusDeviceHistoryController extends BaseCrudController<BusDeviceHist
         return "device:history";
     }
 
+    @PostMapping("/query/page")
+    @SaCheckPermission("bus:history:query")
+    @ApiOperation(value = "分页(输注查询)查询",notes = "权限:【bus:history:query】")
+    public R<IPage<BusDeviceHistoryEntity>> page(@RequestBody @Validated DeviceHistoryQuery query){
+        return R.success(historyService.pageQuery(query));
+    }
+
     @Override
     public BaseService<? extends Mapper<BusDeviceHistoryEntity>, BusDeviceHistoryEntity, String> getService() {
         return historyService;

+ 5 - 1
coffee-system/src/main/java/com/coffee/bus/controller/BusDeviceManualController.java

@@ -1,6 +1,7 @@
 package com.coffee.bus.controller;
 
 import cn.dev33.satoken.SaManager;
+import cn.dev33.satoken.annotation.SaCheckPermission;
 import cn.dev33.satoken.stp.StpLogic;
 import cn.hutool.core.util.StrUtil;
 import com.baomidou.mybatisplus.core.mapper.Mapper;
@@ -40,13 +41,15 @@ public class BusDeviceManualController {
     private final LocalBusDeviceManualService deviceManualService;
 
     @PostMapping("/edit")
+    @SaCheckPermission("device:manual:edit")
     @ApiOperation(value = "编辑病人信息",notes = "编辑病人信息,权限【device:manual:edit】")
     public R edit(@RequestBody DeviceManualVo entity){
-//        deviceManualService.update(entity.getManual(),entity.getClinic());
+        deviceManualService.edit(entity.getManual(),entity.getClinic());
         return R.success();
     }
 
     @PostMapping("/save")
+    @SaCheckPermission("device:manual:save")
     @ApiOperation(value = "新增病人信息",notes = "新增病人信息,权限【device:manual:save】")
     public R save(@RequestBody DeviceManualVo entity){
         deviceManualService.save(entity.getManual(),entity.getClinic());
@@ -54,6 +57,7 @@ public class BusDeviceManualController {
     }
 
     @PostMapping("/no_page")
+    @SaCheckPermission("device:manual:query")
     @ApiOperation(value = "查询其他监控输注列表,不分页",notes = "新增病人信息,权限【device:manual:query】")
     public R<List<ManualMonitorResult>> list(@RequestBody ManualMonitorQuery query){
         return R.success(deviceManualService.selectMonitor(query));

+ 1 - 0
coffee-system/src/main/java/com/coffee/bus/controller/BusDeviceRunningController.java

@@ -80,6 +80,7 @@ public class BusDeviceRunningController implements BaseQueryController<BusDevice
     }
 
 
+    
 
 
     /**

+ 18 - 2
coffee-system/src/main/java/com/coffee/bus/controller/BusEvaluationController.java

@@ -1,12 +1,20 @@
 package com.coffee.bus.controller;
 
+import cn.dev33.satoken.annotation.SaCheckPermission;
 import com.baomidou.mybatisplus.core.mapper.Mapper;
+import com.baomidou.mybatisplus.core.metadata.IPage;
 import com.coffee.bus.entity.BusEvaluationEntity;
 import com.coffee.bus.service.LocalBusEvaluationService;
+import com.coffee.bus.service.dto.EvalQuery;
 import com.coffee.common.crud.BaseService;
 import com.coffee.common.crud.controller.BaseCrudController;
+import com.coffee.common.result.R;
 import io.swagger.annotations.Api;
+import io.swagger.annotations.ApiOperation;
 import lombok.AllArgsConstructor;
+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;
 
@@ -22,9 +30,17 @@ import org.springframework.web.bind.annotation.RestController;
 @RequestMapping("/bus/eval")
 @Api(tags = "评价管理",description = "统一权限前缀(bus:eval),bus:eval:add")
 public class BusEvaluationController extends BaseCrudController<BusEvaluationEntity, String> {
-    private final LocalBusEvaluationService scoreService;
+    private final LocalBusEvaluationService evaluationService;
 
 
+
+    @PostMapping("/query/page")
+    @SaCheckPermission("bus:eval:query")
+    @ApiOperation(value = "评价(输注查询)查询",notes = "权限:【bus:eval:query】")
+    public R<IPage<BusEvaluationEntity>> page(@RequestBody @Validated EvalQuery query){
+        return R.success(evaluationService.pageQuery(query));
+    }
+
     /**
      * 权限控制前缀
      * @return
@@ -36,6 +52,6 @@ public class BusEvaluationController extends BaseCrudController<BusEvaluationEnt
 
     @Override
     public BaseService<? extends Mapper<BusEvaluationEntity>, BusEvaluationEntity, String> getService() {
-        return scoreService;
+        return evaluationService;
     }
 }

+ 9 - 0
coffee-system/src/main/java/com/coffee/bus/controller/BusHospitalController.java

@@ -1,6 +1,8 @@
 package com.coffee.bus.controller;
 
 
+import cn.dev33.satoken.annotation.SaCheckPermission;
+import cn.dev33.satoken.annotation.SaMode;
 import com.baomidou.mybatisplus.core.mapper.Mapper;
 import com.coffee.bus.bean.Script;
 import com.coffee.bus.entity.BusHospitalEntity;
@@ -62,4 +64,11 @@ public class BusHospitalController extends BaseCrudController<BusHospitalEntity,
     public R debug(@PathVariable("id") String id,@RequestBody String param){
         return R.success( scriptManager.lookUpHospital(id).exec(param));
     }
+
+    @PostMapping("/validate")
+    @SaCheckPermission(mode = SaMode.OR,value = {"bus:hospital:edit","bus:hospital:add"})
+    @ApiOperation(value = "校验医院名称是否重复",notes = "权限【bus:hospital:edit 或 bus:hospital:edit】")
+    public R<Boolean> validate(@RequestBody String name){
+        return R.success(this.hospitalService.validateName(name));
+    }
 }

+ 125 - 48
coffee-system/src/main/java/com/coffee/bus/controller/BusPatientController.java

@@ -1,10 +1,14 @@
 package com.coffee.bus.controller;
 
+import cn.dev33.satoken.SaManager;
 import cn.dev33.satoken.annotation.SaCheckPermission;
+import cn.dev33.satoken.stp.StpLogic;
 import cn.hutool.core.collection.CollectionUtil;
 import cn.hutool.core.util.StrUtil;
 import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
 import com.baomidou.mybatisplus.core.conditions.update.UpdateWrapper;
+import com.baomidou.mybatisplus.core.mapper.Mapper;
+import com.coffee.bus.controller.vo.GetPatientInfoVo;
 import com.coffee.bus.controller.vo.MonitorFinishedVo;
 import com.coffee.bus.entity.*;
 import com.coffee.bus.enums.DeviceStatusEnum;
@@ -15,6 +19,9 @@ import com.coffee.bus.registry.patient.bean.DeviceTimeSmallInfo;
 import com.coffee.bus.registry.patient.bean.PatientCacheInfo;
 import com.coffee.bus.service.*;
 import com.coffee.bus.service.dto.*;
+import com.coffee.bus.utils.WsPublishUtils;
+import com.coffee.common.crud.BaseService;
+import com.coffee.common.crud.controller.BaseQueryController;
 import com.coffee.common.exception.CustomException;
 import com.coffee.common.result.R;
 import com.coffee.common.result.ResultCode;
@@ -36,8 +43,8 @@ import java.util.stream.Collectors;
 @RestController
 @AllArgsConstructor
 @RequestMapping("/bus/patient")
-@Api(tags = "医院病人管理",description = "关于病人的相关操作")
-public class BusPatientController  {
+@Api(tags = "医院病人管理",description = "关于病人的相关操作,查询操作权限【bus:patient:query】")
+public class BusPatientController  implements BaseQueryController<BusPatientEntity,String> {
     private final LocalBusPatientService patientService;
 
     private final LocalBusDeviceRunningService deviceRunningService;
@@ -49,10 +56,12 @@ public class BusPatientController  {
     private final LocalBusInfusionHistoryService infusionService;
 
     private final LocalBusDeviceManualService manualService;
+
+    private final WsPublishUtils wsPublishUtils;
     @PostMapping("/no_page")
     @SaCheckPermission("bus:patient:query")
     @ApiOperation(value = "输注监控列表",notes = "病人监控管理列表,权限【bus:patient:query】")
-    public R<List<PatientMonitorDomain>> selectPage(@RequestBody PatientMonitorQuery query){
+    public R<List<PatientMonitorResult>> selectPage(@RequestBody PatientMonitorQuery query){
         return R.success(patientService.selectAll(query));
     }
 
@@ -83,30 +92,51 @@ public class BusPatientController  {
             @ApiResponse(code = 500,message = "没有选择病号"),
             @ApiResponse(code =200 ,message = "若存在不可以结束的临床信息,将会把该临床的主泵信息返回",response = BusDeviceRunningEntity.class)
     })
-    public R<List<BusDeviceRunningEntity>> judgeFinished(@RequestBody List<String> patientCodes){
+    public R<Boolean> judgeFinished(@RequestBody List<String> patientCodes){
         if(CollectionUtil.isEmpty(patientCodes)){
             throw new CustomException("请选择一个病患");
         }
 
-        return R.success(deviceRunningService.list(new QueryWrapper<BusDeviceRunningEntity>()
+        return R.success(CollectionUtil.isNotEmpty(deviceRunningService.list(new QueryWrapper<BusDeviceRunningEntity>()
                 .lambda()
                 .select(BusDeviceRunningEntity::getDeviceId,BusDeviceRunningEntity::getPatientCode,BusDeviceRunningEntity::getRunState,BusDeviceRunningEntity::getAlarm)
                 .eq(BusDeviceRunningEntity::getMaster,true)
                 .eq(BusDeviceRunningEntity::getMonitorType,true)
                 .ne(BusDeviceRunningEntity::getRunState, DeviceStatusEnum.Shutdown)
-                .in(BusDeviceRunningEntity::getPatientCode,patientCodes)));
+                .in(BusDeviceRunningEntity::getPatientCode,patientCodes))));
     }
 
-    @PostMapping("/do/finished")
+    @PostMapping("/do/{monitorType}/finished")
     @SaCheckPermission("bus:patient:finished")
     @ApiResponse(code = 4001,message = "病号当前绑定了多个设备,不可结束管理")
-    @ApiOperation(value = "即结束管理",notes = "病患当前绑定主设备必须要在关机、不在服务器、待机中才能结束管理,权限【bus:patient:finished】")
-    public R finished(@RequestBody MonitorFinishedVo monitorFinishedVo, @RequestAttribute("tenantId")@ApiParam(hidden = true) String tenantId){
+    @ApiOperation(value = "结束管理",notes = "病患当前绑定主设备必须要在关机、不在服务器、待机中才能结束管理,权限【bus:patient:finished】")
+    public R finished(@PathVariable("monitorType")@ApiParam(value = "是否为无泵管理 false、无泵 true、有泵",defaultValue = "false" ) boolean haveDevice,
+                      @RequestBody MonitorFinishedVo monitorFinishedVo,
+                      @RequestAttribute("tenantId")@ApiParam(hidden = true) String tenantId){
+        if(haveDevice){
+            R<Boolean> result = monitorFinished(monitorFinishedVo, tenantId);
+            wsPublishUtils.publishMonitorTotalCount(tenantId);
+            return result;
+        }else {
+            return manualFinished(monitorFinishedVo);
+        }
+    }
+
+    /**
+     * 描述: 输注监控结束管理(即使用驼人网络泵产品)
+     * @author lifang
+     * @date 2022/5/10 11:48
+     * @param monitorFinishedVo
+     * @param tenantId
+     * @return R
+     */
+    private R<Boolean> monitorFinished(MonitorFinishedVo monitorFinishedVo, String tenantId){
         List<String> patientCodes = monitorFinishedVo.getPatientCodes();
         if(CollectionUtil.isEmpty(patientCodes)){
             throw new CustomException("请选择一个病患");
         }
         List<PatientOperator<PatientCacheInfo>> patientOperators = patientCodes.stream().map(code -> patientRegistry.getOperator(tenantId, code)).collect(Collectors.toList());
+
         //重复设备
         Optional<PatientOperator<PatientCacheInfo>> existRepeatDevice = patientOperators.stream()
                 .filter(patientOperator -> {
@@ -118,28 +148,41 @@ public class BusPatientController  {
                 })
                 .findAny();
         if(existRepeatDevice.isPresent()){
-            return R.result(ResultCode.PATIENT_DEVICE_REPEAT,String.format("病号【%s】当前绑定了多个设备,请将多余设备结束后结束管理",existRepeatDevice.get().getCode()));
+            return R.fail(String.format("病号【%s】当前绑定了多个设备,请将多余设备结束后结束管理",existRepeatDevice.get().getCode()));
         }
         //组装撤泵信息
         List<ManualUndoConfig> undoConfigs = patientOperators.stream().map(operator ->
-                ManualUndoConfig.of(Collections.singletonList(operator.getBindDeviceId()), operator.getCode(), tenantId,true, monitorFinishedVo.getUndo())
+                ManualUndoConfig.of(Collections.singletonList(operator.getBindDeviceId()), operator.getCode(),operator.getClinicId(), tenantId,true, monitorFinishedVo.getUndo())
         )
-//                .filter(undoConfig -> undoConfig.getDeviceIds() != null && undoConfig.getDeviceIds().size() > 0)
                 .collect(Collectors.toList());
         //病患绑定的有设备,对设备进行撤泵操作,且结束临床
         deviceRunningService.batchUndo(undoConfigs,true);
-        return R.success();
+        return R.success(true);
+    }
+
+    /**
+     * 描述: 其他监控手动结束管理(即未采用驼人网络泵产品)
+     * @author lifang
+     * @date 2022/5/10 11:49
+     * @param monitorFinishedVo
+     * @return R
+     */
+    private R<Boolean> manualFinished(MonitorFinishedVo monitorFinishedVo){
+        List<String> clinicIds = monitorFinishedVo.getClinicIds();
+        if (CollectionUtil.isEmpty(clinicIds)) {
+            throw new CustomException("未选择临床信息");
+        }
+        manualService.finishedMonitor(monitorFinishedVo);
+        return R.success(true);
     }
 
 
-    @PostMapping("/monitor/reset/{patientCode}")
+    @PostMapping("/monitor/reset/{clinicId}")
     @SaCheckPermission("device:patient:edit")
     @ApiOperation(value = "病人当前监控时间重启",notes = "当结束临床后有新的输注信息产生,那么病人监控会重新显示,此时监控时间不会重新计算,需先调用该接口,权限标识为【device:patient:edit】")
-    public R reset(@PathVariable("patientCode")String patientCode){
-        return R.success(patientService.update(new UpdateWrapper<BusPatientEntity>()
-                .lambda()
-                .eq(BusPatientEntity::getCode,patientCode)
-                .set(BusPatientEntity::getTmpFinished,false)));
+    public R reset(@ApiParam("临床id")@PathVariable("clinicId")String clinicId){
+        return R.success(clinicService.update(new UpdateWrapper<BusClinicEntity>().lambda().eq(BusClinicEntity::getId,clinicId)
+                .set(BusClinicEntity::getFinished,false)));
     }
 
 
@@ -148,6 +191,7 @@ public class BusPatientController  {
     @ApiOperation(value = "主泵切换的操作,只切换,不结束",notes = "当出现泵重复状态时,若用户想要进行主泵的切换,调用该接口进行操作,主泵切换完成后,会将副泵自动撤泵,权限标识为【device:patient:shift】")
     public R shift(@RequestBody DeviceShiftConfig shiftConfig){
         deviceRunningService.shift(shiftConfig);
+        wsPublishUtils.publishPatientMonitor(shiftConfig.getPatientCode(),shiftConfig.getTenantId());
         return R.success();
     }
 
@@ -158,7 +202,8 @@ public class BusPatientController  {
         //泵切换完成后,对病号报警解除
         deviceRunningService.undo(undoConfig,false);
         //判断当前病号下是否还存在副泵
-        long count = deviceRunningService.count(new QueryWrapper<BusDeviceRunningEntity>().lambda().eq(BusDeviceRunningEntity::getPatientCode, undoConfig.getPatientCode())
+        long count = deviceRunningService.count(new QueryWrapper<BusDeviceRunningEntity>().lambda()
+                .eq(BusDeviceRunningEntity::getPatientCode, undoConfig.getPatientCode())
                 .eq(BusDeviceRunningEntity::getTenantId, undoConfig.getTenantId())
                 .eq(BusDeviceRunningEntity::getMaster, false)
                 .eq(BusDeviceRunningEntity::getIsUndo, false));
@@ -189,51 +234,83 @@ public class BusPatientController  {
     }
 
 
-    @GetMapping("/monitor/{monitorType}/{patientCode}")
+    @GetMapping("/monitor/{monitorType}/{clinicId}")
     @SaCheckPermission("device:patient:query")
     @ApiOperation(value = "查看病人当前监控详情",notes = "查看病人当前监控详情,权限标识为【device:patient:query】")
-    public R<PatientMonitorResult> monitor(@PathVariable("monitorType")@ApiParam(value = "是否为有泵监控",example = "0、无泵,1、有泵") Boolean haveDevice,@PathVariable("patientCode")@ApiParam(value = "病号") String patientCode){
-        PatientMonitorResult result = new PatientMonitorResult();
+    public R<PatientMonitorDetailResult> monitor(@PathVariable("monitorType")@ApiParam(value = "是否为有泵监控",example = "0、无泵,1、有泵") Boolean haveDevice, @PathVariable("clinicId")@ApiParam(value = "临床id")String clinicId){
+        PatientMonitorDetailResult result = new PatientMonitorDetailResult();
+        BusClinicEntity clinic = clinicService.getById(clinicId);
+        result.setClinic(clinic);
+        if(clinic==null){
+            throw new CustomException("该临床信息不存在,请刷新后重试");
+        }
         if(haveDevice){
-            BusPatientEntity patient = patientService.getOne(new QueryWrapper<BusPatientEntity>().lambda()
-                    .eq(BusPatientEntity::getCode, patientCode).last("limit 1"));
-            BusInfusionHistoryEntity infusion = infusionService.getById(patient.getInfusionId());
-            result.setPatient(patient);
+            BusInfusionHistoryEntity infusion = infusionService.getOne(new QueryWrapper<BusInfusionHistoryEntity>().lambda().eq(BusInfusionHistoryEntity::getClinicId,clinic.getId())
+                    .orderByDesc(BusInfusionHistoryEntity::getStartTime).last("limit 1"));
+            infusion.setAlias(deviceRunningService.getAliasName(infusion.getDeviceId()));
             result.setInfusion(infusion);
             if(StrUtil.isNotEmpty(infusion.getClinicId())){
                 result.setClinic(clinicService.getById(infusion.getClinicId()));
             }
         }else {
             //无泵查看
-            BusClinicEntity clinic = clinicService.getOne(new QueryWrapper<BusClinicEntity>().lambda().eq(BusClinicEntity::getPatientCode, patientCode).eq(BusClinicEntity::getMonitorType, false).orderByDesc(BusClinicEntity::getStartTime).last("limit 1"));
-            if(clinic!=null){
-                result.setClinic(clinic);
-                result.setDeviceManual( manualService.getOne(new QueryWrapper<BusDeviceManualEntity>().lambda().eq(BusDeviceManualEntity::getClinicId, clinic.getId())));
-            }
+            result.setDeviceManual( manualService.getOne(new QueryWrapper<BusDeviceManualEntity>().lambda().eq(BusDeviceManualEntity::getClinicId, clinic.getId())));
         }
         return R.success(result);
     }
 
-    //todo 使用
-    @PostMapping("/syn/{hospitalId}/{patientCode}")
-    @ApiOperation(value = "同步更新患者信息,即等待更新完成后返回更新结果")
-    public DeferredResult<R> syn(@PathVariable("hospitalId") String hospitalId, @PathVariable("patientCode")String patientCode){
-        DeferredResult<R> result = new DeferredResult<>();
-        result.onCompletion(()->{
+    @PostMapping("/stats/status")
+    @SaCheckPermission("device:patient:query")
+    @ApiOperation(value = "按照状态统计病人监控状态数量",notes = "权限【device:patient:query】")
+    public R<MonitorStatusStatsCountResult> statsStatus(){
+        return R.success(patientService.statusStats(null));
+    }
 
-        });
-        result.onTimeout(()->{
-            R.fail("响应超时");
-        });
-        return result;
+
+    @PostMapping("/stats/time")
+    @SaCheckPermission("device:patient:query")
+    @ApiOperation(value = "按照时间统计病人监控数量",notes = "权限【device:patient:query】")
+    public R<MonitorTimeStatsCountResult> statsTime(){
+        return R.success(patientService.timeStats(null));
     }
 
-    //todo
-    @PostMapping("/async/{hospitalId}/{patientCode}")
-    @ApiOperation(value = "异步更新患者信息,即立刻返回更新结果")
-    public R async(@PathVariable("hospitalId") String hospitalId, @PathVariable("patientCode")String patientCode){
-        return R.success();
+
+
+    @PostMapping("/pull/async")
+    @SaCheckPermission("device:patient:pull")
+    @ApiOperation(value = "同步更新患者信息,超时时间默认为10s,超时后数据返回继续处理,输注监控",notes = "权限标识为【bus:patient:pull】")
+    public DeferredResult<R<BusClinicEntity>> syn(@RequestAttribute("tenantId") String tenantId, @RequestBody GetPatientInfoVo vo){
+        return patientService.getPatientInfoFromHis(tenantId,vo.getPatientCode(),vo.getTimeout(),false);
     }
 
+    /**
+     * 描述:
+     * @author lifang
+     * @date 2022/5/15 21:56
+     * @param tenantId
+     * @param vo
+     * @return R
+     */
+    @PostMapping("/pull/sync")
+    @SaCheckPermission("device:patient:pull")
+    @ApiOperation(value = "同步更新患者信息,超时时间默认为10s,超时后数据返回则不进行处理,无泵更新",notes = "权限标识为【bus:patient:pull】")
+    public DeferredResult<R<BusClinicEntity>>  async(@RequestAttribute("tenantId") String tenantId, @RequestBody GetPatientInfoVo vo){
+        return patientService.getPatientInfoFromHis(tenantId,vo.getPatientCode(),vo.getTimeout(),true);
+    }
+
+
+    @Override
+    public BaseService<? extends Mapper<BusPatientEntity>, BusPatientEntity, String> getService() {
+        return patientService;
+    }
 
+    @Override
+    public String getPermissionPrefix() {
+        return "bus:patient:";
+    }
+
+    @Override
+    public StpLogic getStpLogin() {
+        return SaManager.getStpLogic("");
+    }
 }

+ 4 - 1
coffee-system/src/main/java/com/coffee/bus/controller/vo/ClinicStatsVo.java

@@ -3,7 +3,7 @@ package com.coffee.bus.controller.vo;
 import io.swagger.annotations.ApiModel;
 import io.swagger.annotations.ApiModelProperty;
 import lombok.Data;
-
+import java.util.*;
 /**
  * @author lifang
  * @version 1.0.0
@@ -30,4 +30,7 @@ public class ClinicStatsVo {
     private boolean validCount;
     @ApiModelProperty("是否统计无效次数")
     private boolean inValidCount;
+
+    @ApiModelProperty("参数修改id")
+    private List<String> infusionModifyIds;
 }

+ 21 - 0
coffee-system/src/main/java/com/coffee/bus/controller/vo/GetPatientInfoVo.java

@@ -0,0 +1,21 @@
+package com.coffee.bus.controller.vo;
+
+import io.swagger.annotations.ApiModel;
+import io.swagger.annotations.ApiModelProperty;
+import lombok.Data;
+
+/**
+ * @author lifang
+ * @version 1.0.0
+ * @ClassName GetPatientInfoVo.java
+ * @Description TODO
+ * @createTime 2022年05月15日 21:52:00
+ */
+@Data
+@ApiModel("从his获取病人信息")
+public class GetPatientInfoVo {
+    @ApiModelProperty("病号")
+    private String patientCode;
+    @ApiModelProperty("超时时间,单位:秒;默认10s,当超时时间为-1时,若没有拉取到数据则立即返回")
+    private long timeout;
+}

+ 4 - 1
coffee-system/src/main/java/com/coffee/bus/controller/vo/MonitorFinishedVo.java

@@ -18,9 +18,12 @@ import java.util.List;
 @ApiModel("监控结束")
 @Data
 public class MonitorFinishedVo {
-    @ApiModelProperty("结束监控的病号")
+    @ApiModelProperty("结束监控的病号-临床监护必填")
     private List<String> patientCodes;
 
+    @ApiModelProperty("结束监控的临床号-无泵管理必填")
+    private List<String> clinicIds;
+
     @ApiModelProperty("撤泵配置")
     @NotNull(message = "撤泵配置")
     private UndoDeviceConfig undo;

+ 13 - 2
coffee-system/src/main/java/com/coffee/bus/entity/BusClinicEntity.java

@@ -5,8 +5,8 @@ import com.baomidou.mybatisplus.annotation.TableField;
 import com.baomidou.mybatisplus.annotation.TableLogic;
 import com.baomidou.mybatisplus.annotation.TableName;
 import com.baomidou.mybatisplus.extension.handlers.FastjsonTypeHandler;
-import com.baomidou.mybatisplus.extension.handlers.JacksonTypeHandler;
 import com.coffee.bus.bean.HisInfo;
+import com.coffee.bus.service.dto.UndoDeviceConfig;
 import com.coffee.common.entity.TenantGenericEntity;
 import com.coffee.common.enums.SexEnum;
 import com.fasterxml.jackson.annotation.JsonIgnoreProperties;
@@ -43,9 +43,16 @@ public class BusClinicEntity extends TenantGenericEntity<String,String> {
     @ApiModelProperty(value = "手术开始时间")
     private Date startTime;
 
-    @ApiModelProperty(value = "手术结束时间")
+    @TableField
+    @ApiModelProperty("手术监护开始时间,即该临床手术后第一次上传数据时间")
+    private Date monitorStartTime;
+
+    @ApiModelProperty(value = "手术监护结束时间")
     private Date endTime;
 
+    @ApiModelProperty(value = "asa")
+    private String asa;
+
     @ApiModelProperty(value = "患者姓名")
     @Length(max = 255,message = "患者姓名长度不得超过255个字节")
     private String patientName;
@@ -104,6 +111,10 @@ public class BusClinicEntity extends TenantGenericEntity<String,String> {
     @TableLogic(value = "0",delval = "1")
     private Integer isDelete;
 
+    @ApiModelProperty("结束管理(撤泵)配置,仅在 其他监控中使用")
+    @TableField(typeHandler = FastjsonTypeHandler.class)
+    private UndoDeviceConfig undoConfig;
+
     //todo
     @ApiModelProperty(value = "监护类型,1、有泵监护 0、无泵监护")
     @JsonIgnoreProperties(allowGetters = true)

+ 94 - 19
coffee-system/src/main/java/com/coffee/bus/entity/BusDeviceAlarmEntity.java

@@ -1,11 +1,19 @@
 package com.coffee.bus.entity;
 
+import cn.hutool.crypto.asymmetric.Sign;
+import cn.hutool.json.JSONObject;
+import com.baomidou.mybatisplus.annotation.FieldStrategy;
+import com.baomidou.mybatisplus.annotation.TableField;
 import com.baomidou.mybatisplus.annotation.TableName;
+import com.coffee.bus.entity.common.CommonDeviceParam;
 import com.coffee.bus.enums.DeviceAlarmEnum;
+import com.coffee.bus.enums.DeviceStatusEnum;
+import com.coffee.bus.enums.FlowStatusEnum;
 import com.coffee.common.entity.TenantGenericEntity;
 import com.fasterxml.jackson.annotation.JsonIgnoreProperties;
 import io.swagger.annotations.ApiModel;
 import io.swagger.annotations.ApiModelProperty;
+import jdk.nashorn.internal.ir.EmptyNode;
 import lombok.Data;
 import lombok.EqualsAndHashCode;
 import lombok.ToString;
@@ -28,23 +36,15 @@ public class BusDeviceAlarmEntity extends TenantGenericEntity<String,String> {
     @ApiModelProperty(value = "设备唯一编码",readOnly = true)
     private String deviceId;
 
-    @ApiModelProperty(value = "报警信息")
-    private DeviceAlarmEnum alarm;
-
     @ApiModelProperty(value = "报警时间")
-    private Date alarmTime;
-
+    private Date uploadTime;
 
     @ApiModelProperty(value = "报警原因")
     private String cause;
 
-    @ApiModelProperty(value = "报警是否正在进行",hidden = true)
-    @JsonIgnoreProperties(allowSetters = true)
-    private Boolean doing;
-
-
-    @ApiModelProperty(value = "是否已处理 0、未处理,1、已处理,暂未使用")
-    private Boolean dealing;
+    @ApiModelProperty(value = "是否为报警信息",hidden = true)
+    @JsonIgnoreProperties
+    private Boolean alarm;
 
     @ApiModelProperty(value = "报警记录所绑定的历史记录id,后续用于更新操作",hidden = true)
     @JsonIgnoreProperties(allowSetters = true)
@@ -53,20 +53,95 @@ public class BusDeviceAlarmEntity extends TenantGenericEntity<String,String> {
     @ApiModelProperty(value = "输注记录")
     private String infusionId;
 
+    @ApiModelProperty(value = "泵运行状态",readOnly = true)
+    @TableField(updateStrategy = FieldStrategy.IGNORED)
+    private DeviceStatusEnum runState;
 
-    @ApiModelProperty(value = "设备标识",readOnly = true,hidden = true)
-    @JsonIgnoreProperties(allowSetters = true)
-    private String classification;
+    @ApiModelProperty(value = "报警信息",readOnly = true)
+    @TableField(updateStrategy = FieldStrategy.IGNORED)
+    private DeviceAlarmEnum alarmState;
+
+    @ApiModelProperty(value = "输注即将结束提醒",readOnly = true)
+    @TableField(updateStrategy = FieldStrategy.IGNORED)
+    private Boolean warnWillFinished;
+
+    @ApiModelProperty(value = "镇痛不足提醒",readOnly = true)
+    @TableField(updateStrategy = FieldStrategy.IGNORED)
+    private Boolean warnAnalgesicPoor;
+
+    @ApiModelProperty(value = "电量偏低提醒",readOnly = true)
+    @TableField(updateStrategy = FieldStrategy.IGNORED)
+    private Boolean warnLowBattery;
 
-    public static BusDeviceAlarmEntity parseRunningInfo(BusDeviceHistoryEntity history){
+    @ApiModelProperty(value = "加减档提示",readOnly = true)
+    @TableField(updateStrategy = FieldStrategy.IGNORED)
+    private FlowStatusEnum warnFlow;
+
+    public static BusDeviceAlarmEntity parseHistory(BusDeviceHistoryEntity history){
         BusDeviceAlarmEntity entity = new BusDeviceAlarmEntity();
         entity.setDeviceId(history.getDeviceId());
-        entity.setAlarm(history.getAlarm());
-        entity.setAlarmTime(history.getUploadTime());
+        entity.setUploadTime(history.getUploadTime());
+        if (history.getAlarm() != null && !DeviceAlarmEnum.None.equals(history.getAlarm())) {
+            entity.setAlarm(true);
+        }
         entity.setHistoryId(history.getId());
         entity.setInfusionId(history.getInfusionId());
-        entity.setClassification(history.getClassification());
+        entity.setRunState(history.getRunState());
+        entity.setAlarmState(history.getAlarm());
+        entity.setWarnWillFinished(history.getWarnWillFinished());
+        entity.setWarnAnalgesicPoor(history.getWarnAnalgesicPoor());
+        entity.setWarnLowBattery(history.getWarnLowBattery());
+        entity.setWarnFlow(history.getWarnFlow());
         entity.setTenantId(history.getTenantId());
         return entity;
     }
+
+    public static BusDeviceAlarmEntity parseRunning(BusDeviceRunningEntity source){
+        BusDeviceAlarmEntity entity = new BusDeviceAlarmEntity();
+        entity.setDeviceId(source.getDeviceId());
+        entity.setUploadTime(source.getUploadTime());
+        if (source.getAlarm() != null && !DeviceAlarmEnum.None.equals(source.getAlarm())) {
+            entity.setAlarm(true);
+        }
+        entity.setHistoryId(source.getId());
+        entity.setInfusionId(source.getInfusionId());
+        entity.setRunState(source.getRunState());
+        entity.setAlarmState(source.getAlarm());
+        entity.setWarnWillFinished(source.getWarnWillFinished());
+        entity.setWarnAnalgesicPoor(source.getWarnAnalgesicPoor());
+        entity.setWarnLowBattery(source.getWarnLowBattery());
+        entity.setWarnFlow(source.getWarnFlow());
+        entity.setTenantId(source.getTenantId());
+        return entity;
+    }
+
+    public String signParm(Sign sign){
+        JSONObject param = new JSONObject(true);
+        param.putOpt("runState",String.valueOf(this.getRunState()));
+        param.putOpt("alarmState",String.valueOf(this.getAlarmState()));
+        param.putOpt("warnWillFinished",String.valueOf(this.getWarnWillFinished()));
+        param.putOpt("warnAnalgesicPoor",String.valueOf(this.getWarnAnalgesicPoor()));
+        param.putOpt("warnLowBattery",String.valueOf(this.getWarnLowBattery()));
+        param.putOpt("warnFlow",String.valueOf(this.getWarnFlow()));
+        return sign.signHex(param.toString());
+    }
+
+    public static boolean alarmOrWarn(CommonDeviceParam history){
+        if (history.getAlarm() != null && !DeviceAlarmEnum.None.equals(history.getAlarm())) {
+            return true;
+        }
+        if (Boolean.TRUE.equals(history.getWarnAnalgesicPoor())) {
+            return true;
+        }
+        if (Boolean.TRUE.equals(history.getWarnLowBattery())) {
+            return true;
+        }
+        if (Boolean.TRUE.equals(history.getWarnWillFinished())) {
+            return true;
+        }
+        if (history.getWarnFlow()!=null) {
+            return true;
+        }
+        return false;
+    }
 }

+ 13 - 2
coffee-system/src/main/java/com/coffee/bus/entity/BusDeviceEntity.java

@@ -1,5 +1,7 @@
 package com.coffee.bus.entity;
 
+import com.alibaba.fastjson.annotation.JSONField;
+import com.alibaba.fastjson.serializer.SerializerFeature;
 import com.aliyuncs.iot.model.v20180120.QueryDeviceDetailResponse;
 import com.aliyuncs.iot.model.v20180120.QueryDeviceResponse;
 import com.baomidou.mybatisplus.annotation.*;
@@ -60,6 +62,15 @@ public class BusDeviceEntity extends TenantGenericEntity<String,String> {
     @TableField(typeHandler = FastjsonTypeHandler.class,updateStrategy = FieldStrategy.DEFAULT)
     private AliIotConfig config;
 
+
+    @ApiModelProperty(value = "sim卡卡号")
+    @Length(max = 255,message = "sim卡卡号不得超过255个字符")
+    private String simIccid;
+
+    @ApiModelProperty(value = "移动网络运营商")
+    @Length(max = 255,message = "移动网络运营商不得超过255个字符")
+    private String simMno;
+
     @ApiModelProperty(value = "是否启用,0、不启用 1、启用 ")
     private Boolean enable;
 
@@ -76,7 +87,7 @@ public class BusDeviceEntity extends TenantGenericEntity<String,String> {
      * 根据阿里云返回的数据更新设备对象
      * @param data 由queryDeviceDetail接口返回的数据
      */
-    public void setFields(QueryDeviceDetailResponse.Data data) {
+    public void updateFields(QueryDeviceDetailResponse.Data data) {
         this.deviceId = data.getDeviceName();
         this.config.setProductKey(data.getProductKey());
         this.config.setIotId(data.getIotId());
@@ -90,7 +101,7 @@ public class BusDeviceEntity extends TenantGenericEntity<String,String> {
      * 根据设备查询接口返回的数据,更新设备对象
      * @param item
      */
-    public void setFields(QueryDeviceResponse.DeviceInfo item) {
+    public void updateFields(QueryDeviceResponse.DeviceInfo item) {
         this.deviceId = item.getDeviceName();
         this.config.setProductKey(item.getProductKey());
         this.config.setIotId(item.getIotId());

+ 0 - 1
coffee-system/src/main/java/com/coffee/bus/entity/BusDeviceManualEntity.java

@@ -4,7 +4,6 @@ import com.baomidou.mybatisplus.annotation.TableField;
 import com.baomidou.mybatisplus.annotation.TableName;
 import com.baomidou.mybatisplus.extension.handlers.FastjsonTypeHandler;
 import com.coffee.bus.enums.DeviceManualEnum;
-import com.coffee.bus.enums.DeviceTypeEnum;
 import com.coffee.common.entity.GenericEntity;
 import com.fasterxml.jackson.annotation.JsonIgnore;
 import io.swagger.annotations.ApiModel;

+ 33 - 4
coffee-system/src/main/java/com/coffee/bus/entity/BusDeviceRunningEntity.java

@@ -1,15 +1,13 @@
 package com.coffee.bus.entity;
 
 
-import com.baomidou.mybatisplus.annotation.FieldStrategy;
+
 import com.baomidou.mybatisplus.annotation.TableField;
 import com.baomidou.mybatisplus.annotation.TableName;
 import com.coffee.aliyun.utils.*;
 import com.coffee.bus.entity.common.CommonDeviceParam;
-import com.coffee.bus.enums.DeviceAlarmEnum;
 import com.coffee.bus.enums.DeviceStatusEnum;
 import com.coffee.bus.enums.DeviceTypeEnum;
-import com.coffee.common.entity.TenantGenericEntity;
 import com.coffee.common.enums.SexEnum;
 import com.fasterxml.jackson.annotation.*;
 import io.swagger.annotations.ApiModel;
@@ -92,7 +90,7 @@ public class BusDeviceRunningEntity extends CommonDeviceParam<String,String> {
      * @param items
      */
     public void setFiledsByItems(String deviceName, Items items) {
-        this.setDeviceId(deviceName)  ;
+        this.setDeviceId(deviceName);
         this.setClassification( items.getString(PumpParams.classification));
         this.setDataNumber(items.getInteger(PumpParams.dataNumber));
         this.setPatientCode( items.getString(PumpParams.patientCode));
@@ -114,7 +112,38 @@ public class BusDeviceRunningEntity extends CommonDeviceParam<String,String> {
         this.setRunState(DeviceRunStatusUtils.getRunStatus(items.getInteger(PumpParams.runStatus)));
         this.setAlarm(DeviceAlarmUtils.getAlarm(items.getInteger(PumpParams.alarmStatus)));
         // 预报
+    }
 
+    /**
+     * 描述: 开机处理,将无效参数置为空
+     * @author lifang
+     * @date 2022/5/14 10:51
+     * @param
+     * @return void
+     */
+    public BusDeviceRunningEntity startUpHandle(){
+        if (DeviceStatusEnum.StartUp.equals(this.getRunState())&& DeviceTypeEnum.continuous.equals(this.getType())) {
+            return this;
+        }
+        BusDeviceRunningEntity runningEntity = new BusDeviceRunningEntity();
+        runningEntity.setId(this.getId());
+        runningEntity.setAlias(this.getAlias());
+        runningEntity.setDeviceId(this.getDeviceId());
+        runningEntity.setRunState(this.getRunState());
+        runningEntity.setClassification(this.getClassification());
+        runningEntity.setDataNumber(this.getDataNumber());
+        runningEntity.setType(this.getType());
+        runningEntity.setMonitorType(this.getMonitorType());
+        runningEntity.setUploadTime(this.getUploadTime());
+
+
+//        runningEntity.setInfusionModifyId(this.getInfusionModifyId());
+//        f
+//        runningEntity.setRemark(this.getRemark());
+//        runningEntity.setStartTime(this.getStartTime());
+//        runningEntity.setClinicId(this.getClinicId());
+
+        return runningEntity;
     }
 
 

+ 14 - 3
coffee-system/src/main/java/com/coffee/bus/entity/BusEvaluationEntity.java

@@ -9,6 +9,8 @@ import lombok.EqualsAndHashCode;
 import lombok.experimental.Accessors;
 import org.hibernate.validator.constraints.Length;
 
+import javax.validation.constraints.NotNull;
+
 /**
  * <p>
  * 
@@ -25,16 +27,20 @@ import org.hibernate.validator.constraints.Length;
 public class BusEvaluationEntity extends TenantGenericEntity<String,String> {
 
     @ApiModelProperty(value = "病号")
+    @NotNull(groups = Insert.class,message = "病号不可为空")
     @Length(max = 255,message = "病号长度不得超过255个字节")
     public String patientCode;
 
-    @ApiModelProperty(value = "临床号")
+    @ApiModelProperty(value = "输注id,输注监控专用")
+    private String infusionId;
+
+    @ApiModelProperty(value = "临床号,无泵专用")
     @Length(max = 255,message = "临床号长度不得超过255个字节")
     private String clinicId;
 
     @ApiModelProperty(value = "泵号")
     @Length(max = 50,message = "泵号长度不得超过50个字节")
-    private String pumpCode;
+    private String deviceId;
 
     @ApiModelProperty(value = "疼痛评分静止")
     private Integer statics;
@@ -89,10 +95,12 @@ public class BusEvaluationEntity extends TenantGenericEntity<String,String> {
     private Integer satisfaction;
 
 
-    @ApiModelProperty(value = "评价时间",hidden = true)
+    @ApiModelProperty(value = "评价时间")
+    @NotNull(groups = Insert.class,message = "评价时间不可为空")
     private Date evaluateTime;
 
     @ApiModelProperty(value = "评价人")
+    @NotNull(groups = Insert.class,message = "评价人不可为空")
     @Length(max = 255,message = "评价人长度不得超过255个字节")
     private String evaluator;
 
@@ -106,6 +114,9 @@ public class BusEvaluationEntity extends TenantGenericEntity<String,String> {
     @ApiModelProperty(value = "心率")
     private String heartRate;
 
+    @ApiModelProperty(value = "胎心")
+    private String fetalHeartRate;
+
     @ApiModelProperty(value = "呼吸频率")
     private String breathRate;
 

+ 53 - 3
coffee-system/src/main/java/com/coffee/bus/entity/BusHospitalEntity.java

@@ -3,8 +3,12 @@ package com.coffee.bus.entity;
 import com.baomidou.mybatisplus.annotation.*;
 import com.baomidou.mybatisplus.extension.handlers.FastjsonTypeHandler;
 import com.coffee.bus.bean.Script;
+import com.coffee.bus.his.strategy.HisStrategyEnum;
 import com.coffee.common.entity.RecordCreationEntity;
 import com.coffee.common.entity.RecordModifierEntity;
+import com.fasterxml.jackson.annotation.JsonIgnore;
+import com.fasterxml.jackson.annotation.JsonIgnoreProperties;
+import com.fasterxml.jackson.annotation.JsonSetter;
 import io.swagger.annotations.ApiModel;
 import io.swagger.annotations.ApiModelProperty;
 import lombok.Data;
@@ -69,9 +73,58 @@ public class BusHospitalEntity implements RecordModifierEntity, RecordCreationEn
     @TableField(typeHandler = FastjsonTypeHandler.class )
     private GeoPoint coordinate;
 
+    @TableField(typeHandler = FastjsonTypeHandler.class)
+    private Script script;
+
+    @ApiModelProperty("医院唯一编码,自动生成")
+    @JsonIgnoreProperties(allowGetters = true)
+    private String code;
+
+    @ApiModelProperty("医院脚本是否在线")
+    private Boolean scriptOnline;
+
+    @ApiModelProperty("设备数量")
+    private Integer deviceCount;
+
+    @ApiModelProperty("气泡报警数量")
+    private Integer bubbleCount;
+
+    @ApiModelProperty("堵塞报警数量")
+    private Integer jamCount;
+
+    @ApiModelProperty("极限报警数量")
+    private Integer limitCount;
+
+    @ApiModelProperty("未装药盒报警数量")
+    private Integer noBoxCount;
+
+    @ApiModelProperty("电机失控报警数量")
+    private Integer outOfControlCount;
+
+    @ApiModelProperty("镇痛不足提醒数量")
+    private Integer warnAnalgesicPoorCount;
+
+    @ApiModelProperty(" 不在服务区数量")
+    private Integer noSignalCount;
+
+    @ApiModelProperty(" 机械报警数量")
+    private Integer machineCount;
+
+    @ApiModelProperty("电量耗尽报警数量")
+    private Integer lowBatteryCount;
+
+    @ApiModelProperty("低输注报警数量")
+    private Integer lowestCount;
+
+    @ApiModelProperty("返厂维护报警数量")
+    private Integer maintainCount;
+
     @TableField(fill = FieldFill.INSERT)
     private String createBy;
 
+    @ApiModelProperty("接受his数据的策略, 1(默认)、获取病人全部信息 2、获取病人部分信息 3、获取病人最新信息")
+    private HisStrategyEnum strategy;
+
     @TableField(fill = FieldFill.INSERT_UPDATE)
     private String updateBy;
 
@@ -85,9 +138,6 @@ public class BusHospitalEntity implements RecordModifierEntity, RecordCreationEn
     @TableLogic(value = "0",delval = "1")
     private Integer isDelete;
 
-    @TableField(typeHandler = FastjsonTypeHandler.class)
-    private Script script;
-
     @Data
     public static class  GeoPoint{
         private String lon;

+ 6 - 3
coffee-system/src/main/java/com/coffee/bus/entity/BusInfusionHistoryEntity.java

@@ -50,6 +50,10 @@ public class BusInfusionHistoryEntity extends CommonDeviceParam<String,String> {
     @ApiModelProperty(value = "输注开始时间,即本次运行开机时间",readOnly = true)
     private Date startTime;
 
+    @ApiModelProperty("泵别名")
+    @TableField(exist = false)
+    private String alias;
+
     @ApiModelProperty(value = "是否已撤泵,0、未撤泵1、已撤泵")
     @JsonIgnore
     private Boolean isUndo;
@@ -132,8 +136,8 @@ public class BusInfusionHistoryEntity extends CommonDeviceParam<String,String> {
         entity.setWarnWillFinished(running.getWarnAnalgesicPoor());
         entity.setAlarm(running.getAlarm());
 
-        //若当前临床信息不存在,则将时间戳置为 1971/01/01 01:01:01 todo
-        entity.setClinicStartTime(new Date(31510861L));
+        //若当前临床信息不存在,则将时间戳置为 3000/01/01 01:01:01
+        entity.setClinicStartTime(new Date(32503654861L));
         return entity;
     }
 
@@ -163,7 +167,6 @@ public class BusInfusionHistoryEntity extends CommonDeviceParam<String,String> {
         this.setRunState(DeviceRunStatusUtils.getRunStatus(items.getInteger(PumpParams.runStatus)));
         this.setAlarm(DeviceAlarmUtils.getAlarm(items.getInteger(PumpParams.alarmStatus)));
         // 预报
-
     }
 
 }

+ 114 - 4
coffee-system/src/main/java/com/coffee/bus/entity/BusInfusionModifyEntity.java

@@ -5,8 +5,6 @@ import cn.hutool.json.JSONObject;
 import com.baomidou.mybatisplus.annotation.FieldStrategy;
 import com.baomidou.mybatisplus.annotation.TableField;
 import com.baomidou.mybatisplus.annotation.TableName;
-import com.coffee.bus.entity.common.CommonDeviceParam;
-import com.coffee.bus.entity.common.DeviceProperties;
 import com.coffee.bus.enums.DeviceTypeEnum;
 import com.coffee.common.entity.TenantGenericEntity;
 import com.fasterxml.jackson.annotation.JsonIgnoreProperties;
@@ -37,7 +35,7 @@ import java.util.Date;
 @Accessors(chain = true)
 @TableName(value = "bus_infusion_modify",autoResultMap = true)
 @ApiModel(value="设备输注参数修改记录", description="当输注参数发生修改时,在此表中进行记录")
-public class BusInfusionModifyEntity extends DeviceProperties<String,String> {
+public class BusInfusionModifyEntity extends TenantGenericEntity<String,String> {
 
     @ApiModelProperty(value = "输注记录")
     private String infusionId;
@@ -45,14 +43,126 @@ public class BusInfusionModifyEntity extends DeviceProperties<String,String> {
     @ApiModelProperty(value = "参数修改时间")
     private Date modifyTime;
 
+    @ApiModelProperty(value = "网络泵id",readOnly = true)
+    private String deviceId;
 
+    @ApiModelProperty(value = "数据分类号,标识某些数据属于同一个输注",readOnly = true)
+    @JsonIgnoreProperties(allowSetters = true)
+    private String classification;
+
+    @ApiModelProperty(value = "数据编号",readOnly = true)
+    @JsonIgnoreProperties(allowSetters = true)
+    private Integer dataNumber;
+
+    @ApiModelProperty(value = "泵类型",readOnly = true)
+    @TableField(updateStrategy = FieldStrategy.NEVER)
+    private DeviceTypeEnum type;
+
+    @ApiModelProperty(value = "总量",readOnly = true)
+    @Max(value = 999,message = "总量最大值不得超过999")
+    @Min(value = 0,message ="总量最小值不得超过0" )
+    private Integer totalDose;
+
+    @ApiModelProperty(value = "公共参数-首次量",readOnly = true)
+    @Max(value = 50,message = "首次量最大值不得超过50")
+    @Min(value = 0,message ="首次量最小值不得超过0" )
+    private Integer firstDose;
+
+
+    @ApiModelProperty(value = "公共参数-剩余量",readOnly = true)
+    private BigDecimal remainDose;
+
+    @ApiModelProperty(value = "公共参数-已输入量",readOnly = true)
+    private BigDecimal inputDose;
+
+    @ApiModelProperty(value = "公共参数-追加量",readOnly = true)
+    @DecimalMax(value = "10",message = "PCA追加量最大值不得超过10")
+    @DecimalMin(value = "0",message ="PCA追加量最小值不得超过0" )
+    private BigDecimal appendDose;
+
+    @ApiModelProperty(value = "公共参数-追加锁时",readOnly = true)
+    @DecimalMax(value = "99",message = "PCA追加量最大值不得超过99")
+    @DecimalMin(value = "1",message ="PCA追加量最小值不得超过0" )
+    private BigDecimal appendLockTime;
+
+    @ApiModelProperty(value = "公共参数-极限量",readOnly = true)
+    @DecimalMax(value = "90",message = "PCA追加量最大值不得超过90")
+    @DecimalMin(value = "0",message ="PCA追加量最小值不得超过0" )
+    private BigDecimal maxDose;
+
+    @ApiModelProperty(value = "公共参数-自控锁时",readOnly = true)
+    private Integer selfControlLockTime;
+
+    @ApiModelProperty(value = "公共参数-自控次数",readOnly = true)
+    private Integer selfControlCount;
+
+    @ApiModelProperty(value = "公共参数-pca有效次数",readOnly = true)
+    private Integer pcaValidCount;
+
+    @ApiModelProperty(value = "公共参数-pca无效次数",readOnly = true)
+    private Integer pcaInvalidCount;
+
+    @ApiModelProperty(value = "公共参数-pca总按次数",readOnly = true)
+    private Integer pcaTotalCount;
+
+    @ApiModelProperty(value = "持续泵参数-持续量",readOnly = true)
+    @DecimalMax(value = "50",message = "持续给液量最大值不得超过50")
+    @DecimalMin(value = "0",message ="持续给液量最小值不得超过0" )
+    private BigDecimal continueDose;
+
+    @ApiModelProperty(value = "脉冲泵参数-脉冲量",readOnly = true)
+    @Max(value = 20,message = "脉冲量最大值不得超过20")
+    @Min(value = 0,message ="脉冲量最小值不得超过0" )
+    private Integer pulseDose;
+
+    @ApiModelProperty(value = "脉冲泵参数-脉冲锁时",readOnly = true)
+    @Max(value = 90,message = "脉冲锁时最大值不得超过90")
+    @Min(value = 30,message ="脉冲锁时最小值不得超过30" )
+    private Integer pulseLockTime;
+
+    @ApiModelProperty(value = "脉冲泵参数-脉冲首次锁时",readOnly = true)
+    @Max(value = 60,message = "脉冲首次锁时最大值不得超过60")
+    @Min(value = 0,message ="脉冲首次锁时最小值不得超过0" )
+    private Integer pulseFirstLockTime;
+
+    @ApiModelProperty(value = "智能泵参数-加档周期",readOnly = true)
+    @DecimalMax(value = "10",message = "加档周期最大值不得超过10")
+    @DecimalMin(value = "0.5",message ="加档周期最小值不得超过0.5" )
+    private BigDecimal flowUpCycle;
+
+    @ApiModelProperty(value = "智能泵参数-减档周期",readOnly = true)
+    @DecimalMax(value = "10",message = "减档周期最大值不得超过10")
+    @DecimalMin(value = "0.5",message ="减档周期最小值不得超过0.5" )
+    private BigDecimal flowDownCycle;
+
+    @ApiModelProperty(value = "智能泵参数-计次",readOnly = true)
+    @DecimalMax(value = "10",message = "PCA追加量最大值不得超过10")
+    @DecimalMin(value = "1",message ="PCA追加量最小值不得超过1" )
+    private BigDecimal flowCount;
+
+    @ApiModelProperty(value = "智能泵参数-上限",readOnly = true)
+    @DecimalMax(value = "50",message = "智能泵上限值最大值不得超过90")
+    @DecimalMin(value = "1",message ="智能泵上限值最小值不得超过0" )
+    private BigDecimal flowUpLimit;
+
+    @ApiModelProperty(value = "智能泵参数-下限",readOnly = true)
+    @DecimalMax(value = "50",message = "智能泵下限值最大值不得超过50")
+    @DecimalMin(value = "0.1",message ="智能泵下限值最小值不得超过0.1" )
+    private BigDecimal flowDownLimit;
+
+    @ApiModelProperty(value = "智能泵参数-自调比例",readOnly = true)
+    @DecimalMax(value = "95",message = "自调比例不得超过95")
+    @DecimalMin(value = "0",message ="自调比例最小值不得超过0" )
+    private BigDecimal flowAdjustRate;
+
+    @ApiModelProperty(value = "公共参数-电量",readOnly = true)
+    private Integer electricQuantity;
     public static BusInfusionModifyEntity parseRunningInfo(BusDeviceRunningEntity running){
         BusInfusionModifyEntity entity = new BusInfusionModifyEntity();
         entity.setDeviceId(running.getDeviceId());
         entity.setTenantId(running.getTenantId());
         entity.setInfusionId(running.getInfusionId());
         entity.setType(running.getType());
-
         entity.setClassification(running.getClassification());
         entity.setTotalDose(running.getTotalDose());
         entity.setFirstDose(running.getFirstDose());

+ 0 - 13
coffee-system/src/main/java/com/coffee/bus/entity/BusPatientEntity.java

@@ -43,18 +43,6 @@ public class BusPatientEntity extends TenantGenericEntity<String,String> {
     @ApiModelProperty("病号最新的输注记录")
     private String infusionId;
 
-    @TableField
-    @ApiModelProperty("病人此次监护开始时间")
-    private Date monitorStartTime;
-
-    @TableField
-    @ApiModelProperty("此次监护医生是否已手动结束,以此表示来计算监护时长")
-    private Boolean tmpFinished;
-
-    @TableField
-    @ApiModelProperty("病人最后一次手动监护结束时间")
-    private Date monitorEndTime;
-
     @TableField
     @ApiModelProperty("病人最后的手术id,若病人手术信息暂不存在,则先置为-1")
     private String clinicId;
@@ -78,7 +66,6 @@ public class BusPatientEntity extends TenantGenericEntity<String,String> {
         patient.setName(clinic.getPatientName());
         patient.setGender(clinic.getPatientGender());
         patient.setClinicId(clinic.getId());
-        patient.setTmpFinished(clinic.getFinished());
         patient.setTenantId(clinic.getTenantId());
         return patient;
     }

+ 2 - 0
coffee-system/src/main/java/com/coffee/bus/entity/PatientDeviceRepeatDomain.java

@@ -47,5 +47,7 @@ public class PatientDeviceRepeatDomain {
     private Date infusionStartTime;
     @ApiModelProperty("是否为主泵")
     private Boolean master;
+    @ApiModelProperty("手术id")
+    private String clinicId;
 
 }

+ 0 - 230
coffee-system/src/main/java/com/coffee/bus/entity/PatientMonitorDomain.java

@@ -1,230 +0,0 @@
-package com.coffee.bus.entity;
-
-import cn.hutool.core.util.StrUtil;
-import com.coffee.bus.enums.*;
-import com.coffee.common.enums.SexEnum;
-import com.fasterxml.jackson.annotation.JsonIgnore;
-import io.swagger.annotations.ApiModel;
-import io.swagger.annotations.ApiModelProperty;
-import lombok.Data;
-
-import java.math.BigDecimal;
-import java.util.Date;
-
-/**
- * @author lifang
- * @version 1.0.0
- * @ClassName PatientMonitorDomain.java
- * @Description TODO
- * @createTime 2022年04月21日 15:57:00
- */
-@ApiModel("病人监控实体")
-@Data
-public class PatientMonitorDomain {
-    @ApiModelProperty(value = "病号")
-    private String patientCode;
-
-    @ApiModelProperty(value = "病人名称")
-    private String patientName;
-
-    @ApiModelProperty(value = "性别")
-    private SexEnum gender;
-
-    @ApiModelProperty(value = "病人报警信息",example = "泵重复,无泵")
-    private PatientAlarmEnum patientAlarm;
-
-    @ApiModelProperty(value = "设备id")
-    private String deviceId;
-
-    @ApiModelProperty(value = "泵别名")
-    private String deviceAlias;
-
-    @ApiModelProperty(value = "临床号")
-    private String clinicId;
-
-    @ApiModelProperty(value = "病区")
-    private String ward;
-
-    @ApiModelProperty(value = "床号")
-    private String bedNo;
-
-    @ApiModelProperty(value = "总量")
-    private Integer totalDose;
-
-    @ApiModelProperty(value = "公共参数-首次量")
-    private Integer firstDose;
-
-    @ApiModelProperty(value = "公共参数-电量",readOnly = true)
-    private Integer electricQuantity;
-
-    @ApiModelProperty(value = "公共参数-剩余量")
-    private BigDecimal remainDose;
-
-    @ApiModelProperty(value = "公共参数-已输入量")
-    private BigDecimal inputDose;
-
-    @ApiModelProperty(value = "公共参数-追加量")
-    private BigDecimal appendDose;
-
-    @ApiModelProperty(value = "公共参数-追加锁时")
-    private BigDecimal appendLockTime;
-
-    @ApiModelProperty(value = "公共参数-极限量")
-    private BigDecimal maxDose;
-
-    @ApiModelProperty(value = "公共参数-自控锁时")
-    private BigDecimal selfControlLockTime;
-
-    @ApiModelProperty(value = "公共参数-自控次数")
-    private BigDecimal selfControlCount;
-
-    @ApiModelProperty(value = "公共参数-pca有效次数")
-    private Integer pcaValidCount;
-
-    @ApiModelProperty(value = "公共参数-pca无效次数")
-    private Integer pcaInvalidCount;
-
-    @ApiModelProperty(value = "公共参数-pca总按次数")
-    private Integer pcaTotalCount;
-
-    @ApiModelProperty(value = "持续泵参数-持续量")
-    private BigDecimal continueDose;
-
-    @ApiModelProperty(value = "脉冲泵参数-脉冲量")
-    private Integer pulseDose;
-
-    @ApiModelProperty(value = "脉冲泵参数-脉冲锁时")
-    private Integer pulseLockTime;
-
-    @ApiModelProperty(value = "脉冲泵参数-脉冲首次锁时")
-    private Integer pulseFirstLockTime;
-
-    @ApiModelProperty(value = "智能泵参数-加档周期")
-    private BigDecimal flowUpCycle;
-
-    @ApiModelProperty(value = "智能泵参数-减档周期")
-    private BigDecimal flowDownCycle;
-
-    @ApiModelProperty(value = "智能泵参数-计次")
-    private BigDecimal flowCount;
-
-    @ApiModelProperty(value = "智能泵参数-上限")
-    private BigDecimal flowUpLimit;
-
-    @ApiModelProperty(value = "智能泵参数-下限")
-    private BigDecimal flowDownLimit;
-
-    @ApiModelProperty(value = "智能泵参数-自调比例")
-    private BigDecimal flowAdjustRate;
-
-
-    @ApiModelProperty(value = "泵运行状态")
-    private DeviceStatusEnum deviceRunState;
-
-    @ApiModelProperty(value = "报警信息")
-    private DeviceAlarmEnum deviceAlarm;
-
-    @ApiModelProperty(value = "输注开始时间,即本次运行开机时间")
-    private Date infusionStartTime;
-
-    @ApiModelProperty(value = "备注")
-    private String remark;
-
-    @ApiModelProperty(value = "泵类型")
-    private DeviceTypeEnum deviceType;
-
-    @ApiModelProperty(value = "麻醉医生")
-    private String anaDoctor;
-
-    @ApiModelProperty(value = "麻醉方式")
-    private String anaType;
-
-    @ApiModelProperty(value = "镇痛方式")
-    private String analType;
-
-    @ApiModelProperty(value = "手术医生")
-    private String surgeryDoctor;
-
-    @ApiModelProperty(value = "手术名称")
-    private String surgeryName;
-
-    @ApiModelProperty(value = "当前病人是否已结束临床,根据此参数+监护开始时间计算总监护时间",
-            notes = "false:监护时长=当前时间-监护开始时间 ,true:监护时长=监护结束时间-监护开始时间")
-    private Boolean clinicFinished;
-
-    @ApiModelProperty("当前病人监护结束时间")
-    private Date monitorEndTime;
-
-    @ApiModelProperty("当前病人监护开始时间")
-    private Date monitorStartTime;
-
-    @ApiModelProperty(value = "输注即将结束提醒",hidden = true)
-    @JsonIgnore
-    private Boolean warnWillFinished;
-
-    @ApiModelProperty(value = "镇痛不足提醒",hidden = true)
-    @JsonIgnore
-    private Boolean warnAnalgesicPoor;
-
-    @ApiModelProperty(value = "电量偏低提醒",hidden = true)
-    @JsonIgnore
-    private Boolean warnLowBattery;
-
-    @ApiModelProperty(value = "加减档提示",readOnly = true)
-    @JsonIgnore
-    private FlowStatusEnum warnFlow;
-
-    @ApiModelProperty("提醒字段")
-    private String warns;
-
-    private void judgeWarnWillFinished() {
-        if(!Boolean.TRUE.equals(this.warnWillFinished)){
-           return;
-        }
-        if (StrUtil.isEmpty(this.warns)) {
-            this.warns="输注即将结束;";
-        }else {
-            this.warns=this.warns+"输注即将结束;";
-        }
-    }
-
-    private void judgeWarnAnalgesicPoor() {
-        if(!Boolean.TRUE.equals(this.warnAnalgesicPoor)){
-            return;
-        }
-        if (StrUtil.isEmpty(this.warns)) {
-            this.warns="镇痛不足;";
-        }else {
-            this.warns=this.warns+"镇痛不足;";
-        }
-    }
-
-    private void judgeWarnLowBattery() {
-        if(!Boolean.TRUE.equals(this.warnLowBattery)){
-            return;
-        }
-        if (StrUtil.isEmpty(this.warns)) {
-            this.warns="电量偏低;";
-        }else {
-            this.warns=this.warns+"电量偏低;";
-        }
-    }
-
-    private void judgeWarnFlow() {
-        if(this.warnFlow==null){
-            return;
-        }
-        if (StrUtil.isEmpty(this.warns)) {
-            this.warns=warnFlow.getText()+";";
-        }else {
-            this.warns=this.warns+warnFlow.getText()+";";
-        }
-    }
-
-    public void handleWarn(){
-        judgeWarnAnalgesicPoor();
-        judgeWarnFlow();
-        judgeWarnLowBattery();
-        judgeWarnWillFinished();
-    }
-}

+ 4 - 10
coffee-system/src/main/java/com/coffee/bus/entity/common/CommonDeviceParam.java

@@ -4,20 +4,11 @@ import com.baomidou.mybatisplus.annotation.FieldStrategy;
 import com.baomidou.mybatisplus.annotation.TableField;
 import com.coffee.bus.enums.DeviceAlarmEnum;
 import com.coffee.bus.enums.DeviceStatusEnum;
-import com.coffee.bus.enums.DeviceTypeEnum;
 import com.coffee.bus.enums.FlowStatusEnum;
-import com.coffee.common.entity.TenantGenericEntity;
-import com.fasterxml.jackson.annotation.JsonIgnoreProperties;
 import io.swagger.annotations.ApiModelProperty;
 import lombok.Data;
 import lombok.experimental.Accessors;
 
-import javax.validation.constraints.DecimalMax;
-import javax.validation.constraints.DecimalMin;
-import javax.validation.constraints.Max;
-import javax.validation.constraints.Min;
-import java.math.BigDecimal;
-
 /**
  * @author lifang
  * @version 1.0.0
@@ -38,16 +29,19 @@ public class CommonDeviceParam<PK,TN>  extends DeviceProperties<PK,TN>  {
     private DeviceAlarmEnum alarm;
 
     @ApiModelProperty(value = "输注即将结束提醒",readOnly = true)
+    @TableField(updateStrategy = FieldStrategy.IGNORED)
     private Boolean warnWillFinished;
 
     @ApiModelProperty(value = "镇痛不足提醒",readOnly = true)
+    @TableField(updateStrategy = FieldStrategy.IGNORED)
     private Boolean warnAnalgesicPoor;
 
     @ApiModelProperty(value = "电量偏低提醒",readOnly = true)
+    @TableField(updateStrategy = FieldStrategy.IGNORED)
     private Boolean warnLowBattery;
 
     @ApiModelProperty(value = "加减档提示",readOnly = true)
-    @TableField(updateStrategy = FieldStrategy.DEFAULT)
+    @TableField(updateStrategy = FieldStrategy.IGNORED)
     private FlowStatusEnum warnFlow;
 
 }

+ 1 - 0
coffee-system/src/main/java/com/coffee/bus/enums/ConfigEnum.java

@@ -4,6 +4,7 @@ import com.baomidou.mybatisplus.annotation.IEnum;
 import com.coffee.bus.bean.config.EvalConfig;
 import com.coffee.bus.bean.config.OtherConfig;
 import com.coffee.bus.bean.config.UndoConfig;
+import com.fasterxml.jackson.annotation.JsonFormat;
 import lombok.AllArgsConstructor;
 import lombok.Getter;
 

+ 1 - 6
coffee-system/src/main/java/com/coffee/bus/enums/DeviceAlarmEnum.java

@@ -31,12 +31,7 @@ public enum DeviceAlarmEnum  implements IEnum<Integer> {
     Finished(6,"输液结束"),
     LowBattery(7,"电量耗尽报警"),
     OutOfControl(8,"电机失控报警"),
-    Machine(9,"机械故障"),
-    NoSignal(10,"不在服务区"),
-
-
-
-    ;
+    Machine(9,"机械故障"),;
 
 
     @Getter

+ 1 - 0
coffee-system/src/main/java/com/coffee/bus/enums/DeviceManualEnum.java

@@ -16,6 +16,7 @@ import lombok.Getter;
 @AllArgsConstructor
 @JsonFormat(shape = JsonFormat.Shape.OBJECT)
 public enum DeviceManualEnum implements IEnum<Integer> {
+    none(-1,"无设备"),
     machine(0,"机械泵"),
     electronPulse(1,"电子脉冲泵"),
     electron(2,"电子泵"),

+ 2 - 1
coffee-system/src/main/java/com/coffee/bus/enums/DeviceStatusEnum.java

@@ -27,7 +27,8 @@ public enum DeviceStatusEnum  implements IEnum<Integer> {
     StartUp(1,"开机"),
     Running(2,"运行"),
     Pause(3,"暂停"),
-    Waiting(4,"待机")
+    Waiting(4,"待机"),
+    NoSignal(5,"不在服务区")
     ;
 
 

+ 1 - 1
coffee-system/src/main/java/com/coffee/bus/enums/DeviceTypeEnum.java

@@ -16,7 +16,7 @@ import lombok.Getter;
 @AllArgsConstructor
 @JsonFormat(shape = JsonFormat.Shape.OBJECT)
 public enum DeviceTypeEnum implements IEnum<Integer> {
-    no(0,"无泵"),
+    no(0,"未知"),
     continuous(1,"网络泵"),
     intelligent(2,"智能泵"),
     pulse(3,"脉冲泵"),

+ 81 - 0
coffee-system/src/main/java/com/coffee/bus/his/HisRequest.java

@@ -0,0 +1,81 @@
+package com.coffee.bus.his;
+
+import com.coffee.bus.entity.BusClinicEntity;
+import com.coffee.common.result.R;
+import com.fasterxml.jackson.annotation.JsonIgnore;
+import lombok.AllArgsConstructor;
+import lombok.Builder;
+import lombok.Data;
+import lombok.NoArgsConstructor;
+import org.springframework.web.context.request.async.DeferredResult;
+
+import javax.validation.constraints.NotNull;
+import java.io.Serializable;
+import java.util.Date;
+import java.util.concurrent.TimeUnit;
+
+/**
+ * @author lifang
+ * @version 1.0.0
+ * @ClassName HisRequest.java
+ * @Description 向his脚本发起的请求
+ * @createTime 2022年05月14日 16:38:00
+ */
+@Data
+@Builder
+@NoArgsConstructor
+@AllArgsConstructor
+public class HisRequest implements Serializable {
+    /**
+     *
+     * 消息id
+     *
+     */
+    private String messageId;
+
+    /**
+     *
+     * 病号
+     *
+     */
+    private String patientCode;
+
+    /**
+     *
+     * 超时时间
+     *
+     */
+    @JsonIgnore
+    private long timeout;
+
+    /**
+     *
+     * 超时时间单位
+     *
+     */
+    @JsonIgnore
+    private TimeUnit timeUnit;
+
+    /**
+     *
+     * 发送时间时间戳
+     *
+     */
+    private Date timestamp;
+
+    /**
+     *
+     * 请求是否为同步请求
+     *
+     */
+    private boolean sync;
+
+    /**
+     *
+     * 用户响应结果
+     *
+     */
+    @JsonIgnore
+    @NotNull
+    private DeferredResult<R<BusClinicEntity>> result;
+}

+ 73 - 0
coffee-system/src/main/java/com/coffee/bus/his/HisResponse.java

@@ -0,0 +1,73 @@
+package com.coffee.bus.his;
+
+import lombok.Data;
+
+import java.util.Date;
+
+/**
+ * @author lifang
+ * @version 1.0.0
+ * @ClassName HisResponse.java
+ * @Description his脚本返回的响应
+ * @createTime 2022年05月14日 16:38:00
+ */
+@Data
+public class HisResponse {
+    /**
+     *
+     * 消息id
+     *
+     */
+    private String messageId;
+
+    /**
+     *
+     * 病号
+     *
+     */
+    private String patientCode;
+
+    /**
+     *
+     * 响应类型
+     *
+     */
+    private String type;
+
+    /**
+     *
+     * 查询是否成功
+     *
+     */
+    private boolean success;
+
+    /**
+     *
+     * 请求是否为同步请求
+     *
+     */
+    private boolean sync;
+
+    /**
+     *
+     * 响应内容
+     *
+     */
+    private Object context;
+
+    /**
+     *
+     * 当查询失败时错误信息
+     *
+     */
+    private String errorMsg;
+
+    /**
+     *
+     * 响应时间戳
+     *
+     */
+    private Date timestamp;
+
+
+}

+ 331 - 0
coffee-system/src/main/java/com/coffee/bus/his/HisScriptSession.java

@@ -0,0 +1,331 @@
+package com.coffee.bus.his;
+
+import cn.hutool.core.bean.BeanUtil;
+import cn.hutool.core.collection.CollectionUtil;
+import cn.hutool.core.date.DateField;
+import cn.hutool.core.util.RandomUtil;
+import cn.hutool.core.util.StrUtil;
+import cn.hutool.extra.spring.SpringUtil;
+import cn.hutool.json.JSON;
+import cn.hutool.json.JSONArray;
+import cn.hutool.json.JSONUtil;
+import com.baomidou.mybatisplus.core.conditions.update.UpdateWrapper;
+import com.baomidou.mybatisplus.core.toolkit.IdWorker;
+import com.coffee.bus.entity.BusClinicEntity;
+import com.coffee.bus.entity.BusHospitalEntity;
+import com.coffee.bus.listener.event.bean.HisEvent;
+import com.coffee.bus.script.DefaultParse;
+import com.coffee.bus.script.ExecuteResult;
+import com.coffee.bus.script.ScriptManager;
+import com.coffee.bus.script.ScriptParse;
+import com.coffee.bus.service.LocalBusClinicService;
+import com.coffee.bus.service.LocalBusHospitalService;
+import com.coffee.common.cache.ClusterConfigStorage;
+import com.coffee.common.cache.value.Value;
+import com.coffee.common.result.R;
+import lombok.extern.slf4j.Slf4j;
+import org.springframework.data.redis.core.RedisTemplate;
+import org.springframework.util.Assert;
+import org.springframework.web.context.request.async.DeferredResult;
+import org.tio.core.ChannelContext;
+import org.tio.core.Tio;
+import org.tio.core.utils.TioUtils;
+import org.tio.websocket.common.WsResponse;
+
+import javax.validation.constraints.NotNull;
+import java.util.*;
+import java.util.concurrent.ConcurrentHashMap;
+import java.util.concurrent.Executors;
+import java.util.concurrent.ScheduledExecutorService;
+import java.util.concurrent.TimeUnit;
+
+/**
+ * @author lifang
+ * @version 1.0.0
+ * @ClassName HisSession.java
+ * @Description his脚本会话
+ * @createTime 2022年05月13日 17:30:00
+ */
+@Slf4j
+public class HisScriptSession {
+    private String hospitalId;
+    private ChannelContext channelContext;
+    private ScriptManager scriptManager;
+    private LocalBusClinicService clinicService;
+    private ClusterConfigStorage clusterConfigStorage;
+    private LocalBusHospitalService hospitalService;
+    private Map<String,HisRequest> hisRequestMap=new ConcurrentHashMap<>();
+    public HisScriptSession(String hospitalId, ChannelContext channelContext, ScriptManager scriptManager,
+                            RedisTemplate redisTemplate, LocalBusClinicService clinicService, LocalBusHospitalService hospitalService) {
+        this.hospitalId = hospitalId;
+        this.channelContext = channelContext;
+        this.scriptManager = scriptManager;
+        this.clinicService = clinicService;
+        this.hospitalService=hospitalService;
+        init(redisTemplate,hospitalId,hospitalService);
+    }
+
+    public HisScriptSession(String hospitalId, ScriptManager scriptManager, RedisTemplate redisTemplate, LocalBusClinicService clinicService,LocalBusHospitalService hospitalService) {
+        this.hospitalId = hospitalId;
+        this.scriptManager = scriptManager;
+        this.clinicService = clinicService;
+        this.hospitalService=hospitalService;
+        init(redisTemplate,hospitalId,hospitalService);
+    }
+
+    private void init(RedisTemplate redisTemplate,String hospitalId,LocalBusHospitalService hospitalService){
+        BusHospitalEntity hospital = hospitalService.getById(hospitalId);
+        if(hospital==null){
+            throw new RuntimeException(String.format("医院{%s}不存在,获取医院脚本会话失败",hospitalId));
+        }
+        clusterConfigStorage=new ClusterConfigStorage(redisTemplate,hospitalId);
+        clusterConfigStorage.setConfig("info",hospital);
+    }
+
+    /**
+     * 描述: 更新医院信息
+     * @author lifang
+     * @date 2022/5/15 1:03
+     * @param hospital
+     * @return void
+     */
+    public void refresh(BusHospitalEntity hospital){
+        clusterConfigStorage.setConfig("info",hospital);
+    }
+
+    /**
+     * 描述: 获取医院信息
+     * @author lifang
+     * @date 2022/5/16 9:29
+     * @param
+     * @return BusHospitalEntity
+     */
+    public BusHospitalEntity getHospitalInfo(){
+        return clusterConfigStorage.getConfig("info").as(BusHospitalEntity.class);
+    }
+    /**
+     * 描述: 同步拉取病人信息,超时后该次请求不再处理
+     * @author lifang
+     * @date 2022/5/14 16:24
+     * @param patientCode
+     * @param timeout
+     * @param unit
+     * @return BusClinicEntity
+     */
+    public  DeferredResult<R<BusClinicEntity>>  syncGetPatientInfo(String patientCode, long timeout, TimeUnit unit){
+//        if (!isOnline()) {
+//            throw new CustomException("医院不在线,拉取信息失败");
+//        }
+        String messageId = IdWorker.getIdStr();
+        DeferredResult<R<BusClinicEntity>> result = new DeferredResult<>(unit.toMillis(timeout));
+        HisRequest request = HisRequest.builder()
+                .messageId(messageId)
+                .patientCode(patientCode)
+                .sync(true)
+                .timeout(timeout)
+                .timeUnit(unit)
+                .result(result)
+                .timestamp(new Date())
+                .build();
+        sendRequest(channelContext,request);
+        result.onTimeout(()->{
+            BusClinicEntity clinic = clinicService.recentClinicByPatientCode(hospitalId, patientCode);
+            if(clinic==null){
+                result.setResult(R.fail("拉取信息超时,请稍后再试"));
+            }else {
+                result.setResult(R.success(clinic));
+            }
+            //超时后不在响应
+            hisRequestMap.remove(messageId);
+        });
+        return result;
+    };
+
+    /**
+     * 描述: 异步拉取病人信息
+     *  当异步拉取超时时,若需要返回临床信息,则从数据库中拉取最新数据返回
+     * @author lifang
+     * @date 2022/5/14 16:26
+     * @param patientCode 病号
+     * @param timeout 超时时间
+     * @param unit 时间单位
+     * @param needResult 是否需要返回结果
+     * @return BusClinicEntity
+     */
+    public  DeferredResult<R<BusClinicEntity>>  asyncGetPatientInfo(String patientCode,long timeout, TimeUnit unit,boolean needResult){
+        String messageId = IdWorker.getIdStr();
+        DeferredResult<R<BusClinicEntity>> result = new DeferredResult<>(unit.toMillis(timeout));
+        HisRequest request = HisRequest.builder()
+                .messageId(messageId)
+                .patientCode(patientCode)
+                .sync(true)
+                .timeout(timeout)
+                .timeUnit(unit)
+                .result(result)
+                .timestamp(new Date())
+                .build();
+        result.onTimeout(()->{
+            if(needResult){
+                BusClinicEntity clinic = clinicService.recentClinicByPatientCode(hospitalId, patientCode);
+                if(clinic==null){
+                    result.setResult(R.fail("拉取信息超时,请稍后再试"));
+                }else {
+                    result.setResult(R.success(clinic));
+                }
+            }
+            hisRequestMap.remove(messageId);
+        });
+        //将数据存储到数据库
+        sendRequest(channelContext,request);
+        return result;
+    };
+
+    /**
+     * 描述: 处理his返回数据并返回开始时间最大的手术信息
+     * @author lifang
+     * @date 2022/5/14 15:02
+     * @param text
+     * @param patientCode
+     * @return BusClinicEntity 开始时间最大的手术信息
+     */
+    public BusClinicEntity handle(String text,String patientCode){
+        ScriptParse script = scriptManager.getById(hospitalId);
+        if(script==null){
+            log.warn("没有获取到医院{}的解析脚本信息,不处理该条数据",hospitalId);
+            script=new DefaultParse();
+        }
+        if(StrUtil.isBlank(text)){
+            return null;
+        }
+        ExecuteResult exec = script.exec(text);
+        JSON result=null;
+        try {
+            result = exec.getIfSuccess();
+        }catch (Exception e){
+            log.error("数据解析后转化为json失败,{},",text,e.getMessage());
+            return null;
+        }
+        //数据解析完成后发布
+        JSONArray jsonArray = JSONUtil.parseArray(result);
+        List<BusClinicEntity> sources = JSONUtil.toList(jsonArray, BusClinicEntity.class);
+        if(CollectionUtil.isEmpty(sources)){
+            return null;
+        }else {
+            sources.sort(Comparator.comparing(BusClinicEntity::getStartTime));
+            SpringUtil.publishEvent(new HisEvent(this,sources,hospitalId,patientCode));
+            return sources.get(sources.size()-1);
+        }
+    }
+
+    /**
+     * 描述:his会话与ws通道绑定
+     * @author lifang
+     * @date 2022/5/14 15:02
+     * @param channelContext
+     * @return void
+     */
+    public void bindChannel(ChannelContext channelContext){
+        this.channelContext=channelContext;
+        if(TioUtils.checkBeforeIO(channelContext)){
+            hospitalService.update(new UpdateWrapper<BusHospitalEntity>().lambda().eq(BusHospitalEntity::getId,hospitalId).set(BusHospitalEntity::getScriptOnline,true));
+            refresh(hospitalService.getById(hospitalId));
+        }
+    };
+
+
+    /**
+     * 描述: 医院his脚本是否在线
+     * @author lifang
+     * @date 2022/5/14 15:02
+     * @param
+     * @return boolean
+     */
+    public boolean isOnline(){
+        return channelContext!=null&&TioUtils.checkBeforeIO(channelContext);
+    }
+
+    /**
+     * 描述:
+     * @author lifang
+     * @date 2022/5/14 16:37
+     * @param channelContext
+     * @param request
+     * @return void
+     */
+    private ScheduledExecutorService executorService = Executors.newSingleThreadScheduledExecutor();
+    private void sendRequest(ChannelContext channelContext,HisRequest request){
+        hisRequestMap.put(request.getMessageId(),request);
+        Tio.send(channelContext, WsResponse.fromText(JSONUtil.toJsonStr(request),"utf-8"));
+        executorService.schedule(()->{
+            BusClinicEntity clinicEntity = clinicService.recentClinicByPatientCode("1", request.getPatientCode());
+            List<BusClinicEntity> clinic = new ArrayList<>();
+            HisResponse hisResponse = new HisResponse();
+            hisResponse.setMessageId(request.getMessageId());
+            hisResponse.setSuccess(true);
+            hisResponse.setTimestamp(new Date());
+            hisResponse.setPatientCode(request.getPatientCode());
+            for (int i = 0; i < 5; i++) {
+                clinicEntity.setId(null);
+                clinicEntity.setMonitorType(true);
+                clinicEntity.setName("新的临床数据"+i);
+                BusClinicEntity c = new BusClinicEntity();
+                BeanUtil.copyProperties(clinicEntity,c);
+                c.setStartTime(RandomUtil.randomDate(new Date(), DateField.HOUR_OF_DAY,-30,10));
+                clinic.add(c);
+            }
+            hisResponse.setContext(JSONUtil.toJsonStr(clinic));
+            response(hisResponse);
+        },1,TimeUnit.SECONDS);
+    }
+
+    public void response(HisResponse hisResponse){
+        //判断是否成功,是否超时
+        String messageId = hisResponse.getMessageId();
+        Assert.hasText(messageId,"his脚本响应数据无messageId");
+        HisRequest hisRequest = hisRequestMap.remove(messageId);
+        if(hisResponse.isSuccess()){
+            //同步请求当超时之后,不再处理数据
+            boolean sync = hisResponse.isSync();
+            if (hisRequest == null) {
+                log.warn("响应[{}]请求不存在,或已超时",messageId);
+                if(sync){
+                    return;
+                }
+                //正常响应
+                handle(Value.simple(hisResponse.getContext()).asString(), hisResponse.getPatientCode());
+            }else {
+                Date responseTimestamp = hisResponse.getTimestamp();
+                Date requestTimestamp = hisRequest.getTimestamp();
+                long timeout = hisRequest.getTimeout();
+                TimeUnit timeUnit = hisRequest.getTimeUnit();
+                DeferredResult<R<BusClinicEntity>> result = hisRequest.getResult();
+                if (requestTimestamp.getTime()+timeUnit.toMillis(timeout)>responseTimestamp.getTime()) {
+                    log.warn("请求[{}]已超时,请求时间[{}],响应时间[{}],是否为同步请求[{}]",messageId,requestTimestamp,responseTimestamp,sync);
+                    if(sync){
+                        result.setErrorResult("响应超时");
+                        return;
+                    }
+                }
+                //正常响应
+                BusClinicEntity clinic = handle(Value.simple(hisResponse.getContext()).asString(), hisResponse.getPatientCode());
+                result.setResult(R.success(clinic));
+            }
+        }else {
+            if (hisRequest != null) {
+                log.warn("医院[{}]拉取信息失败,失败原因[{}]",hospitalId,hisResponse.getErrorMsg());
+                hisRequest.getResult().setResult(R.fail("更新失败,失败原因["+ hisResponse.getErrorMsg()+"]"));
+            }
+        }
+    }
+
+    /**
+     * 描述: 会话下线
+     * @author lifang
+     * @date 2022/5/15 21:45
+     * @param
+     * @return void
+     */
+    public void offline() {
+        hospitalService.update(new UpdateWrapper<BusHospitalEntity>().lambda().eq(BusHospitalEntity::getId,hospitalId).set(BusHospitalEntity::getScriptOnline,false));
+    }
+}

+ 82 - 0
coffee-system/src/main/java/com/coffee/bus/his/HisScriptSessionManager.java

@@ -0,0 +1,82 @@
+package com.coffee.bus.his;
+
+import com.coffee.bus.script.ScriptManager;
+import com.coffee.bus.service.LocalBusClinicService;
+import com.coffee.bus.service.LocalBusHospitalService;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.data.redis.core.RedisTemplate;
+import org.springframework.stereotype.Component;
+
+import java.util.Map;
+import java.util.concurrent.ConcurrentHashMap;
+
+/**
+ * @author lifang
+ * @version 1.0.0
+ * @ClassName HisScriptConnectionManager.java
+ * @Description his脚本管理
+ * @createTime 2022年05月13日 16:10:00
+ */
+@Component
+public class HisScriptSessionManager {
+    private Map<String,HisScriptSession> sessionMap=new ConcurrentHashMap<>();
+    private LocalBusClinicService clinicService;
+    private ScriptManager scriptManager;
+    private RedisTemplate redisTemplate;
+    private LocalBusHospitalService hospitalService;
+
+    @Autowired
+    public HisScriptSessionManager(LocalBusClinicService clinicService, ScriptManager scriptManager, RedisTemplate redisTemplate, LocalBusHospitalService hospitalService) {
+        this.clinicService = clinicService;
+        this.scriptManager = scriptManager;
+        this.redisTemplate = redisTemplate;
+        this.hospitalService = hospitalService;
+    }
+
+    /**
+     * 描述: 根据医院id获取会话
+     * @author lifang
+     * @date 2022/5/15 1:06
+     * @param hospitalId
+     * @return HisScriptSession
+     */
+    public HisScriptSession get(String hospitalId){
+        return sessionMap.computeIfAbsent(hospitalId,k->register(hospitalId));
+    };
+
+    /**
+     * 描述: 注册医院会话信息
+     * @author lifang
+     * @date 2022/5/15 1:07
+     * @param hospitalId
+     * @return HisScriptSession
+     */
+    public HisScriptSession register(String hospitalId){
+        return new HisScriptSession(hospitalId, scriptManager,redisTemplate, clinicService,hospitalService);
+    }
+
+    /**
+     * 描述: 注销医院会话
+     * @author lifang
+     * @date 2022/5/15 1:07
+     * @param hospitalId
+     * @return HisScriptSession
+     */
+    public HisScriptSession unregister(String hospitalId){
+        return sessionMap.remove(hospitalId);
+    }
+
+
+
+    /**
+     * 描述: 判断医院脚本是否在线
+     * @author lifang
+     * @date 2022/5/15 1:08
+     * @param hospitalId
+     * @return boolean
+     */
+    public boolean isOnline(String hospitalId){
+        return sessionMap.get(hospitalId).isOnline();
+    };
+
+}

+ 25 - 0
coffee-system/src/main/java/com/coffee/bus/his/strategy/HisStrategyEnum.java

@@ -0,0 +1,25 @@
+package com.coffee.bus.his.strategy;
+
+import com.baomidou.mybatisplus.annotation.IEnum;
+import lombok.AllArgsConstructor;
+import lombok.Getter;
+
+/**
+ * @author lifang
+ * @version 1.0.0
+ * @ClassName HisStrategyEnum.java
+ * @Description TODO
+ * @createTime 2022年05月12日 14:52:00
+ */
+@AllArgsConstructor
+@Getter
+public enum  HisStrategyEnum  implements IEnum<Integer> {
+    ALL(1,"拉取所有的病人数据"),
+    PART(2,"拉取部分病人数据(例、最新三个月)"),
+    NEW(3,"只拉取最新的病人数据"),
+    ;
+
+    private Integer value;
+    private String text;
+
+}

+ 49 - 0
coffee-system/src/main/java/com/coffee/bus/his/strategy/HisStrategyHandler.java

@@ -0,0 +1,49 @@
+package com.coffee.bus.his.strategy;
+
+import com.coffee.bus.entity.BusClinicEntity;
+import java.util.*;
+/**
+ * @author lifang
+ * @version 1.0.0
+ * @ClassName HisHandlerStrategy.java
+ * @Description his系统数据的处理策略
+ * @createTime 2022年05月12日 09:33:00
+ */
+public interface HisStrategyHandler {
+    /**
+     * 描述: 处理策略id,保证id的唯一性
+     * @author lifang
+     * @date 2022/5/12 9:35
+     * @param
+     * @return String
+     */
+    String getId();
+
+    /**
+     * 描述: 处理策略描述
+     * @author lifang
+     * @date 2022/5/12 9:35
+     * @param
+     * @return String
+     */
+    String getDescription();
+    /**
+     * 描述: 策略处理实现逻辑
+     * @author lifang
+     * @date 2022/5/12 9:38
+     * @param source his数据来源
+     * @param target 本地数据来源
+     * @return void
+     */
+    void handle(List<BusClinicEntity> source,List<BusClinicEntity> target);
+
+    /**
+     * 描述: 判断该his数据是否适用该策略
+     * @author lifang
+     * @date 2022/5/12 9:39
+     * @param source his数据来源
+     * @param target 数据库存储数据
+     * @return boolean
+     */
+    boolean apply(List<BusClinicEntity> source,List<BusClinicEntity> target);
+}

+ 30 - 0
coffee-system/src/main/java/com/coffee/bus/his/strategy/HisStrategyManager.java

@@ -0,0 +1,30 @@
+package com.coffee.bus.his.strategy;
+
+import java.util.*;
+/**
+ * @author lifang
+ * @version 1.0.0
+ * @ClassName HisStrategyManager.java
+ * @Description TODO
+ * @createTime 2022年05月12日 14:45:00
+ */
+public interface HisStrategyManager<T extends HisStrategyHandler> {
+    /**
+     * 描述: 获取策略类型
+     * @author lifang
+     * @date  14:48
+     * @param
+     * @see  HisStrategyEnum
+     * @return String
+     */
+    HisStrategyEnum getType();
+
+    /**
+     * 描述: 获取策略处理器
+     * @author lifang
+     * @date 2022/5/12 14:48
+     * @param
+     * @return List<HisStrategyHandler>
+     */
+    List<T> getHandlers();
+}

+ 36 - 0
coffee-system/src/main/java/com/coffee/bus/his/strategy/HisStrategyManagerRegister.java

@@ -0,0 +1,36 @@
+package com.coffee.bus.his.strategy;
+
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.stereotype.Component;
+
+import java.util.*;
+
+/**
+ * @author lifang
+ * @version 1.0.0
+ * @ClassName HisStrategyManagerRegister.java
+ * @Description his策略管理注册器
+ * @createTime 2022年05月12日 16:30:00
+ */
+@Component
+public class HisStrategyManagerRegister {
+    private Map<HisStrategyEnum,HisStrategyManager<? extends HisStrategyHandler>> map=new HashMap<>();
+
+    @Autowired
+    public HisStrategyManagerRegister(List<HisStrategyManager<? extends HisStrategyHandler>> strategyManagers) {
+        strategyManagers.forEach(manager->{
+            map.merge(manager.getType(),manager,(o1,o2)->{
+                throw new RuntimeException(String.format("his数据处理策略管理器唯一,不可重复[%s]",o1.getType()));
+            });
+        });
+    }
+
+    public HisStrategyManager<? extends HisStrategyHandler> get(HisStrategyEnum strategyEnum){
+        if(strategyEnum==null){
+            //采用默认处理器
+            strategyEnum=HisStrategyEnum.ALL;
+        }
+        HisStrategyManager<? extends HisStrategyHandler> manager = map.get(strategyEnum);
+        return manager==null?map.get(HisStrategyEnum.ALL):manager;
+    }
+}

+ 68 - 0
coffee-system/src/main/java/com/coffee/bus/his/strategy/all/EqualsStrategyHandler.java

@@ -0,0 +1,68 @@
+package com.coffee.bus.his.strategy.all;
+
+import cn.hutool.core.collection.CollectionUtil;
+import cn.hutool.json.JSONUtil;
+import com.baomidou.mybatisplus.core.conditions.update.UpdateWrapper;
+import com.coffee.bus.entity.BusClinicEntity;
+import com.coffee.bus.service.LocalBusClinicService;
+import com.coffee.bus.his.strategy.HisStrategyHandler;
+import lombok.AllArgsConstructor;
+import lombok.extern.slf4j.Slf4j;
+import org.springframework.stereotype.Component;
+import org.springframework.transaction.annotation.Transactional;
+
+import java.util.Comparator;
+import java.util.List;
+import java.util.stream.Collectors;
+
+/**
+ * @author lifang
+ * @version 1.0.0
+ * @ClassName EqualsStrategyHandler.java
+ * @Description 从his拉取的数据多于当前数据库存储的数据
+ * his          手术场次: 一  、 二 、 三
+ * 数据库存储    手术场次: 一 、 二 、三
+ * 按照场次对场次相同的手术进行对比,对新增手术进行新增操作
+ * @createTime 2022年05月12日 11:13:00
+ */
+@Component
+@Slf4j
+@AllArgsConstructor
+public class EqualsStrategyHandler implements HisAllStrategyHandler {
+    private final LocalBusClinicService clinicService;
+    @Override
+    public String getId() {
+        return "equal";
+    }
+
+    @Override
+    public String getDescription() {
+        return "拉取的his手术数量和数据库存储的手术数量相等";
+    }
+
+    @Override
+    @Transactional(rollbackFor = Exception.class)
+    public void handle(List<BusClinicEntity> source, List<BusClinicEntity> target) {
+        //空数据不处理
+        if(CollectionUtil.isEmpty(source)){
+            return;
+        }
+        log.info("拉取的his手术数量和数据库存储的手术数量相等,拉取手术信息{},数据库数据{}", JSONUtil.toJsonStr(source),JSONUtil.toJsonStr(target));
+        source.sort(Comparator.comparing(BusClinicEntity::getStartTime));
+        target.sort(Comparator.comparing(BusClinicEntity::getStartTime));
+        for (int i = 0; i < source.size(); i++) {
+            BusClinicEntity targetClinic= source.get(i);
+            if(i<source.size()-1){
+                targetClinic.setFinished(true);
+            }else {
+                targetClinic.setFinished(false);
+            }
+            clinicService.compareFromHis(source.get(i),target.get(i));
+        }
+    }
+
+    @Override
+    public boolean apply(List<BusClinicEntity> source, List<BusClinicEntity> target) {
+        return CollectionUtil.size(source)==CollectionUtil.size(target);
+    }
+}

+ 13 - 0
coffee-system/src/main/java/com/coffee/bus/his/strategy/all/HisAllStrategyHandler.java

@@ -0,0 +1,13 @@
+package com.coffee.bus.his.strategy.all;
+
+import com.coffee.bus.his.strategy.HisStrategyHandler;
+
+/**
+ * @author lifang
+ * @version 1.0.0
+ * @ClassName HisAllStrategyHandler.java
+ * @Description TODO
+ * @createTime 2022年05月12日 14:55:00
+ */
+public interface HisAllStrategyHandler extends HisStrategyHandler {
+}

+ 36 - 0
coffee-system/src/main/java/com/coffee/bus/his/strategy/all/HisAllStrategyManager.java

@@ -0,0 +1,36 @@
+package com.coffee.bus.his.strategy.all;
+
+import com.coffee.bus.his.strategy.HisStrategyEnum;
+import com.coffee.bus.his.strategy.HisStrategyManager;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.stereotype.Component;
+
+import java.util.List;
+
+/**
+ * @author lifang
+ * @version 1.0.0
+ * @ClassName HisAllStrategyManager.java
+ * @Description his拉取病人全部的临床数据
+ * @createTime 2022年05月12日 14:49:00
+ */
+@Component
+public class HisAllStrategyManager  implements HisStrategyManager<HisAllStrategyHandler> {
+
+    private List<HisAllStrategyHandler> handlers;
+
+    @Autowired
+    public HisAllStrategyManager(List<HisAllStrategyHandler> handlers) {
+        this.handlers = handlers;
+    }
+
+    @Override
+    public HisStrategyEnum getType() {
+        return HisStrategyEnum.ALL;
+    }
+
+    @Override
+    public List<HisAllStrategyHandler> getHandlers() {
+        return handlers;
+    }
+}

+ 60 - 0
coffee-system/src/main/java/com/coffee/bus/his/strategy/all/LessToMoreHisStrategyHandler.java

@@ -0,0 +1,60 @@
+package com.coffee.bus.his.strategy.all;
+
+import cn.hutool.core.collection.CollectionUtil;
+import cn.hutool.json.JSONUtil;
+import com.coffee.bus.entity.BusClinicEntity;
+import com.coffee.bus.service.LocalBusClinicService;
+import com.coffee.bus.his.strategy.HisStrategyHandler;
+import lombok.AllArgsConstructor;
+import lombok.extern.slf4j.Slf4j;
+import org.springframework.stereotype.Component;
+import org.springframework.transaction.annotation.Transactional;
+
+import java.util.Comparator;
+import java.util.List;
+
+/**
+ * @author lifang
+ * @version 1.0.0
+ * @ClassName LessToMoreHisStrategyHandler.java
+ * @Description 从his拉取的数据多于当前数据库存储的数据,按照时间先后只更新最新的N场手术数据,其他的数据不做任何处理
+ * his          手术场次: 一  、 二
+ * 数据库存储    手术场次: 一 、 二 、三
+ * @createTime 2022年05月12日 13:53:00
+ */
+@AllArgsConstructor
+@Component
+@Slf4j
+public class LessToMoreHisStrategyHandler implements HisAllStrategyHandler {
+    private final LocalBusClinicService clinicService;
+    @Override
+    public String getId() {
+        return "less-to-more";
+    }
+
+    @Override
+    public String getDescription() {
+        return "拉取his数据少于数据库数据";
+    }
+
+    @Override
+    @Transactional(rollbackFor = Exception.class)
+    public void handle(List<BusClinicEntity> source, List<BusClinicEntity> target) {
+        //当HIS未拉取任何数据时,不做任何处理
+        if(CollectionUtil.isEmpty(source)){
+            return;
+        }
+        log.info("拉取his数据少于数据库数据,拉取手术信息{},数据库数据{}", JSONUtil.toJsonStr(source),JSONUtil.toJsonStr(target));
+        source.sort(Comparator.comparing(BusClinicEntity::getStartTime));
+        target.sort(Comparator.comparing(BusClinicEntity::getStartTime));
+        int subSize = target.size() - source.size();
+        for (int i = 0; i < source.size(); i++) {
+            clinicService.compareFromHis(source.get(i),target.get(subSize+i));
+        }
+    }
+
+    @Override
+    public boolean apply(List<BusClinicEntity> source, List<BusClinicEntity> target) {
+        return CollectionUtil.size(source)<CollectionUtil.size(target);
+    }
+}

+ 75 - 0
coffee-system/src/main/java/com/coffee/bus/his/strategy/all/MoreToLessHisStrategyHandler.java

@@ -0,0 +1,75 @@
+package com.coffee.bus.his.strategy.all;
+
+import cn.hutool.core.collection.CollectionUtil;
+import cn.hutool.json.JSONUtil;
+import com.coffee.bus.entity.BusClinicEntity;
+import com.coffee.bus.service.LocalBusClinicService;
+import com.coffee.bus.his.strategy.HisStrategyHandler;
+import lombok.AllArgsConstructor;
+import lombok.extern.slf4j.Slf4j;
+import org.springframework.stereotype.Component;
+import org.springframework.transaction.annotation.Transactional;
+
+import java.util.*;
+
+/**
+ * @author lifang
+ * @version 1.0.0
+ * @ClassName MoreToLessHisStrategyHandler.java
+ * @Description 从his拉取的数据多于当前数据库存储的数据
+ * his          手术场次: 一  、 二 、 三
+ * 数据库存储    手术场次: 一 、 二
+ * 按照场次对场次相同的手术进行对比,对新增手术进行新增操作
+ * @createTime 2022年05月12日 09:45:00
+ */
+@Component
+@Slf4j
+@AllArgsConstructor
+public class MoreToLessHisStrategyHandler implements HisAllStrategyHandler {
+    private final LocalBusClinicService clinicService;
+    @Override
+    public String getId() {
+        return "more-to-less";
+    }
+
+    @Override
+    public String getDescription() {
+        return "拉取his数据多于数据库数据";
+    }
+
+    @Override
+    @Transactional(rollbackFor = Exception.class)
+    public void handle(List<BusClinicEntity> source, List<BusClinicEntity> target) {
+        if(CollectionUtil.isEmpty(source)){
+            return;
+        }
+        log.info("拉取his数据多于数据库数据,拉取手术信息{},数据库数据{}", JSONUtil.toJsonStr(source),JSONUtil.toJsonStr(target));
+        //所有按照从小到大排序
+        source.sort(Comparator.comparing(BusClinicEntity::getStartTime));
+        List<BusClinicEntity> insert=new LinkedList<>();
+        if (CollectionUtil.isEmpty(target)) {
+            //所有的source都为新增
+            insert.addAll(source);
+        }else {
+            target.sort(Comparator.comparing(BusClinicEntity::getStartTime));
+            //对比修改临床信息
+            int start=0;
+            for (; start < target.size(); start++) {
+                clinicService.compareFromHis(source.get(start),target.get(start));
+            }
+            insert.addAll(source.subList(start,source.size()));
+        }
+        //按照开始时间从大到小排序
+        CollectionUtil.reverse(insert);
+        //新增临床信息
+        insert.forEach(clinicService::insertFromHis);
+        clinicService.setCurrentClinicByHis(insert.get(0));
+    }
+
+    @Override
+    public boolean apply(List<BusClinicEntity> source, List<BusClinicEntity> target) {
+        return CollectionUtil.size(source)>CollectionUtil.size(target);
+    }
+
+
+}

+ 78 - 0
coffee-system/src/main/java/com/coffee/bus/his/strategy/onlynew/DefaultHisNewStrategyHandler.java

@@ -0,0 +1,78 @@
+package com.coffee.bus.his.strategy.onlynew;
+
+import cn.hutool.core.collection.CollectionUtil;
+import cn.hutool.json.JSONUtil;
+import com.coffee.bus.entity.BusClinicEntity;
+import com.coffee.bus.service.LocalBusClinicService;
+import lombok.AllArgsConstructor;
+import lombok.extern.slf4j.Slf4j;
+import org.springframework.stereotype.Component;
+import org.springframework.transaction.annotation.Transactional;
+
+import java.util.Comparator;
+import java.util.List;
+
+/**
+ * @author lifang
+ * @version 1.0.0
+ * @ClassName DefaultHisNewStrategyHandler.java
+ * @Description TODO
+ * @createTime 2022年05月12日 15:01:00
+ */
+@Component
+@AllArgsConstructor
+@Slf4j
+public class DefaultHisNewStrategyHandler implements HisNewStrategyHandler {
+    private final LocalBusClinicService clinicService;
+    @Override
+    public String getId() {
+        return "new-clinic";
+    }
+
+    @Override
+    public String getDescription() {
+        return "拉取his只获取最新的一跳病人数据,对其进行处理";
+    }
+
+    @Override
+    @Transactional(rollbackFor = Exception.class)
+    public void handle(List<BusClinicEntity> source, List<BusClinicEntity> target) {
+        if(CollectionUtil.isEmpty(source)){
+            return;
+        }
+        log.info("拉取his只获取最新的一跳病人数据,对其进行处理,拉取手术信息{},数据库数据{}", JSONUtil.toJsonStr(source),JSONUtil.toJsonStr(target));
+        //是否插入新的数据
+        boolean insert=true;
+        //是否为设置为当前的临床数据
+        boolean isCurrent=false;
+        BusClinicEntity clinic = source.get(0);
+        if(CollectionUtil.isEmpty(target)){
+            isCurrent=true;
+        }else {
+            target.sort(Comparator.comparing(BusClinicEntity::getStartTime));
+            //获取最新的临床数据
+            BusClinicEntity newClinic = target.get(target.size() - 1);
+            if(clinic.getStartTime().equals(newClinic.getStartTime())){
+                //临床数据未发生变化
+                clinicService.compareFromHis(clinic,newClinic);
+                insert=false;
+            }else if(clinic.getStartTime().after(newClinic.getStartTime())){
+                isCurrent=true;
+            }else {
+                //旧的数据丢掉
+                insert=false;
+            }
+        }
+        if(insert){
+            clinicService.insertFromHis(clinic);
+        }
+        if(isCurrent){
+            clinicService.setCurrentClinicByHis(clinic);
+        }
+    }
+
+    @Override
+    public boolean apply(List<BusClinicEntity> source, List<BusClinicEntity> target) {
+        return CollectionUtil.isNotEmpty(source);
+    }
+}

+ 13 - 0
coffee-system/src/main/java/com/coffee/bus/his/strategy/onlynew/HisNewStrategyHandler.java

@@ -0,0 +1,13 @@
+package com.coffee.bus.his.strategy.onlynew;
+
+import com.coffee.bus.his.strategy.HisStrategyHandler;
+
+/**
+ * @author lifang
+ * @version 1.0.0
+ * @ClassName HisPartStrategyHandler.java
+ * @Description TODO
+ * @createTime 2022年05月12日 14:59:00
+ */
+public interface HisNewStrategyHandler extends HisStrategyHandler {
+}

+ 32 - 0
coffee-system/src/main/java/com/coffee/bus/his/strategy/onlynew/HisNewStrategyManager.java

@@ -0,0 +1,32 @@
+package com.coffee.bus.his.strategy.onlynew;
+
+import com.coffee.bus.his.strategy.HisStrategyEnum;
+import com.coffee.bus.his.strategy.HisStrategyManager;
+import lombok.AllArgsConstructor;
+import lombok.extern.slf4j.Slf4j;
+import org.springframework.stereotype.Component;
+
+import java.util.List;
+
+/**
+ * @author lifang
+ * @version 1.0.0
+ * @ClassName HisNewStrategyManager.java
+ * @Description his只拉取病人最新的历史数据
+ * @createTime 2022年05月12日 14:50:00
+ */
+@Component
+@AllArgsConstructor
+@Slf4j
+public class HisNewStrategyManager implements HisStrategyManager<HisNewStrategyHandler> {
+    private final List<HisNewStrategyHandler> handlers;
+    @Override
+    public HisStrategyEnum getType() {
+        return HisStrategyEnum.NEW;
+    }
+
+    @Override
+    public List<HisNewStrategyHandler> getHandlers() {
+        return handlers;
+    }
+}

+ 90 - 0
coffee-system/src/main/java/com/coffee/bus/his/strategy/part/DefaultHisPartStrategyHandler.java

@@ -0,0 +1,90 @@
+package com.coffee.bus.his.strategy.part;
+
+import cn.hutool.core.collection.CollectionUtil;
+import cn.hutool.json.JSONUtil;
+import com.coffee.bus.entity.BusClinicEntity;
+import com.coffee.bus.his.strategy.all.HisAllStrategyHandler;
+import com.coffee.bus.his.strategy.onlynew.HisNewStrategyHandler;
+import com.coffee.bus.service.LocalBusClinicService;
+import lombok.AllArgsConstructor;
+import lombok.extern.slf4j.Slf4j;
+import org.springframework.stereotype.Component;
+import org.springframework.transaction.annotation.Transactional;
+
+import java.util.Comparator;
+import java.util.List;
+
+/**
+ * @author lifang
+ * @version 1.0.0
+ * @ClassName DefaultHisPartStrategyHandler.java
+ * @Description TODO
+ * @createTime 2022年05月12日 15:01:00
+ */
+@Component
+@Slf4j
+@AllArgsConstructor
+public class DefaultHisPartStrategyHandler implements HisNewStrategyHandler {
+    private final LocalBusClinicService clinicService;
+    private final List<HisAllStrategyHandler> allStrategyHandlers;
+    @Override
+    public String getId() {
+        return "part-clinic";
+    }
+
+    @Override
+    public String getDescription() {
+        return "拉取his只获取一部分病人数据(如,最近3个月),对其进行处理";
+    }
+
+    @Override
+    @Transactional(rollbackFor = Exception.class)
+    public void handle(List<BusClinicEntity> source, List<BusClinicEntity> target) {
+        if(CollectionUtil.isEmpty(source)){
+            return;
+        }
+        log.info("拉取his只获取一部分病人数据,拉取手术信息{},数据库数据{}", JSONUtil.toJsonStr(source),JSONUtil.toJsonStr(target));
+        source.sort(Comparator.comparing(BusClinicEntity::getStartTime));
+        if(CollectionUtil.isEmpty(target)){
+            //只插入
+            insert(source);
+        }else {
+            //his拉取数据中最早的手术开始时间
+            BusClinicEntity earliest = source.get(0);
+            target.sort(Comparator.comparing(BusClinicEntity::getStartTime));
+            //按照时间比较,找到第一个比his拉取数据大的手术信息
+            int start=0;
+            for (; start < target.size(); start++) {
+                BusClinicEntity existClinic = target.get(start);
+                if(existClinic.getStartTime().equals(earliest.getStartTime())){
+                    break;
+                }
+                if(existClinic.getStartTime().after(earliest.getStartTime())){
+                    //start下限为0
+                    start=start>0?start-1:0;
+                    break;
+                }
+            }
+            if(start>=target.size()){
+                insert(source);
+            }else {
+                //走全处理的逻辑
+                List<BusClinicEntity> existClinics = target.subList(start, target.size());
+                allStrategyHandlers.stream()
+                        .filter(handler->handler.apply(source,existClinics))
+                        .forEach(handler->handler.handle(source,existClinics));
+            }
+        }
+
+    }
+
+    private void insert(List<BusClinicEntity> source){
+        source.forEach(clinicService::insertFromHis);
+        clinicService.setCurrentClinicByHis(source.get(source.size()-1));
+    }
+
+    @Override
+    public boolean apply(List<BusClinicEntity> source, List<BusClinicEntity> target) {
+        return CollectionUtil.isNotEmpty(source);
+    }
+}

+ 13 - 0
coffee-system/src/main/java/com/coffee/bus/his/strategy/part/HisPartStrategyHandler.java

@@ -0,0 +1,13 @@
+package com.coffee.bus.his.strategy.part;
+
+import com.coffee.bus.his.strategy.HisStrategyHandler;
+
+/**
+ * @author lifang
+ * @version 1.0.0
+ * @ClassName HisPartStrategyHandler.java
+ * @Description TODO
+ * @createTime 2022年05月12日 14:59:00
+ */
+public interface HisPartStrategyHandler extends HisStrategyHandler {
+}

+ 32 - 0
coffee-system/src/main/java/com/coffee/bus/his/strategy/part/HisPartStrategyManager.java

@@ -0,0 +1,32 @@
+package com.coffee.bus.his.strategy.part;
+
+import com.coffee.bus.his.strategy.HisStrategyEnum;
+import com.coffee.bus.his.strategy.HisStrategyManager;
+import lombok.AllArgsConstructor;
+import lombok.extern.slf4j.Slf4j;
+import org.springframework.stereotype.Component;
+
+import java.util.List;
+
+/**
+ * @author lifang
+ * @version 1.0.0
+ * @ClassName HisNewStrategyManager.java
+ * @Description his只拉取病人最新的历史数据
+ * @createTime 2022年05月12日 14:50:00
+ */
+@Component
+@Slf4j
+@AllArgsConstructor
+public class HisPartStrategyManager implements HisStrategyManager<HisPartStrategyHandler> {
+    private final List<HisPartStrategyHandler> handlers;
+    @Override
+    public HisStrategyEnum getType() {
+        return HisStrategyEnum.PART;
+    }
+
+    @Override
+    public List<HisPartStrategyHandler> getHandlers() {
+        return handlers;
+    }
+}

+ 5 - 3
coffee-system/src/main/java/com/coffee/bus/listener/event/bean/HisEvent.java

@@ -18,16 +18,18 @@ import java.time.Clock;
 public class HisEvent extends ApplicationEvent {
     private final String hospitalId;
     private final List<BusClinicEntity> clinics;
-
-    public HisEvent(Object source,List<BusClinicEntity> clinics, @NotNull String hospitalId) {
+    private final String patientCode;
+    public HisEvent(Object source,List<BusClinicEntity> clinics, @NotNull String hospitalId, @NotNull String patientCode) {
         super(source);
         this.hospitalId=hospitalId;
         this.clinics=clinics;
+        this.patientCode=patientCode;
     }
 
-    public HisEvent(Object source, Clock clock, List<BusClinicEntity> clinics, @NotNull String hospitalId) {
+    public HisEvent(Object source, Clock clock, List<BusClinicEntity> clinics, @NotNull String hospitalId, @NotNull  String patientCode) {
         super(source, clock);
         this.hospitalId=hospitalId;
         this.clinics=clinics;
+        this.patientCode=patientCode;
     }
 }

+ 14 - 0
coffee-system/src/main/java/com/coffee/bus/mapper/BusClinicMapper.java

@@ -1,9 +1,14 @@
 package com.coffee.bus.mapper;
 
 import com.baomidou.mybatisplus.core.mapper.BaseMapper;
+import com.baomidou.mybatisplus.core.metadata.IPage;
+import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
 import com.coffee.bus.controller.vo.ClinicStatsVo;
 import com.coffee.bus.entity.BusClinicEntity;
 import java.util.*;
+
+import com.coffee.bus.service.dto.ClinicQuery;
+import com.coffee.bus.service.dto.ClinicResult;
 import com.coffee.bus.service.dto.ClinicStatsQueryResult;
 import org.apache.ibatis.annotations.Mapper;
 import org.apache.ibatis.annotations.Param;
@@ -30,4 +35,13 @@ public interface BusClinicMapper extends BaseMapper<BusClinicEntity> {
 
 
     List<ClinicStatsQueryResult> stats(@Param("query") ClinicStatsVo query);
+
+    /**
+     * 描述: 分页查询临床数据
+     * @author lifang
+     * @date 2022/5/10 17:29
+     * @param page
+     * @return IPage<ClinicResult>
+     */
+    IPage<ClinicResult> pageQuery(Page<ClinicResult> page,@Param("query") ClinicQuery query);
 }

+ 6 - 1
coffee-system/src/main/java/com/coffee/bus/mapper/BusDeviceAlarmMapper.java

@@ -1,8 +1,13 @@
 package com.coffee.bus.mapper;
 
 import com.baomidou.mybatisplus.core.mapper.BaseMapper;
+import com.baomidou.mybatisplus.core.metadata.IPage;
+import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
+import com.coffee.bus.entity.BusClinicEntity;
 import com.coffee.bus.entity.BusDeviceAlarmEntity;
+import com.coffee.bus.service.dto.AlarmQuery;
 import org.apache.ibatis.annotations.Mapper;
+import org.apache.ibatis.annotations.Param;
 
 /**
  * @author lifang
@@ -14,5 +19,5 @@ import org.apache.ibatis.annotations.Mapper;
 @Mapper
 public interface BusDeviceAlarmMapper extends BaseMapper<BusDeviceAlarmEntity> {
 
-    void selectCount(BusDeviceAlarmEntity busDeviceAlarmEntity);
+    IPage<BusDeviceAlarmEntity> pageQuery(Page<BusDeviceAlarmEntity> page, @Param("query") AlarmQuery query);
 }

+ 8 - 0
coffee-system/src/main/java/com/coffee/bus/mapper/BusDeviceHistoryMapper.java

@@ -1,8 +1,14 @@
 package com.coffee.bus.mapper;
 
 import com.baomidou.mybatisplus.core.mapper.BaseMapper;
+import com.baomidou.mybatisplus.core.metadata.IPage;
+import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
+import com.coffee.bus.entity.BusDeviceAlarmEntity;
 import com.coffee.bus.entity.BusDeviceHistoryEntity;
+import com.coffee.bus.service.dto.AlarmQuery;
+import com.coffee.bus.service.dto.DeviceHistoryQuery;
 import org.apache.ibatis.annotations.Mapper;
+import org.apache.ibatis.annotations.Param;
 
 /**
  * @author lifang
@@ -13,4 +19,6 @@ import org.apache.ibatis.annotations.Mapper;
  */
 @Mapper
 public interface BusDeviceHistoryMapper extends BaseMapper<BusDeviceHistoryEntity> {
+
+    IPage<BusDeviceHistoryEntity> pageQuery(Page<BusDeviceHistoryEntity> page,@Param("query") DeviceHistoryQuery query);
 }

+ 3 - 1
coffee-system/src/main/java/com/coffee/bus/mapper/BusDeviceManualMapper.java

@@ -1,9 +1,11 @@
 package com.coffee.bus.mapper;
 
 import com.baomidou.mybatisplus.core.mapper.BaseMapper;
+import com.baomidou.mybatisplus.core.metadata.IPage;
 import com.coffee.bus.entity.BusDeviceManualEntity;
 import com.coffee.bus.service.dto.ManualMonitorQuery;
 import com.coffee.bus.service.dto.ManualMonitorResult;
+import com.coffee.bus.service.dto.PatientMonitorResult;
 import org.apache.ibatis.annotations.Mapper;
 import org.apache.ibatis.annotations.Param;
 
@@ -22,5 +24,5 @@ public interface BusDeviceManualMapper extends BaseMapper<BusDeviceManualEntity>
      * 查询其他监控信息列表
      * @return
      */
-    List<ManualMonitorResult> selectMonitor(@Param("query") ManualMonitorQuery query);
+    IPage<ManualMonitorResult> selectMonitor(IPage<ManualMonitorResult> page,@Param("query") ManualMonitorQuery query);
 }

+ 6 - 0
coffee-system/src/main/java/com/coffee/bus/mapper/BusDeviceMapper.java

@@ -1,8 +1,13 @@
 package com.coffee.bus.mapper;
 
 import com.baomidou.mybatisplus.core.mapper.BaseMapper;
+import com.baomidou.mybatisplus.core.metadata.IPage;
+import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
 import com.coffee.bus.entity.BusDeviceEntity;
+import com.coffee.bus.service.dto.DeviceQuery;
+import com.coffee.bus.service.dto.DeviceResult;
 import org.apache.ibatis.annotations.Mapper;
+import org.apache.ibatis.annotations.Param;
 import org.apache.ibatis.annotations.Select;
 
 /**
@@ -29,4 +34,5 @@ public interface BusDeviceMapper extends BaseMapper<BusDeviceEntity> {
      */
     Integer notDelete(String deviceId);
 
+    IPage<DeviceResult> pageQuery(Page<DeviceResult> page,@Param("query") DeviceQuery query);
 }

+ 5 - 0
coffee-system/src/main/java/com/coffee/bus/mapper/BusEvaluationMapper.java

@@ -1,8 +1,12 @@
 package com.coffee.bus.mapper;
 
 import com.baomidou.mybatisplus.core.mapper.BaseMapper;
+import com.baomidou.mybatisplus.core.metadata.IPage;
+import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
 import com.coffee.bus.entity.BusEvaluationEntity;
+import com.coffee.bus.service.dto.EvalQuery;
 import org.apache.ibatis.annotations.Mapper;
+import org.apache.ibatis.annotations.Param;
 
 /**
  * @author lifang
@@ -13,4 +17,5 @@ import org.apache.ibatis.annotations.Mapper;
  */
 @Mapper
 public interface BusEvaluationMapper extends BaseMapper<BusEvaluationEntity> {
+    IPage<BusEvaluationEntity> pageQuery(Page<BusEvaluationEntity> page,@Param("query") EvalQuery query);
 }

+ 4 - 2
coffee-system/src/main/java/com/coffee/bus/mapper/BusPatientMapper.java

@@ -4,7 +4,7 @@ import com.baomidou.mybatisplus.core.mapper.BaseMapper;
 import com.baomidou.mybatisplus.core.metadata.IPage;
 import com.coffee.bus.entity.BusPatientEntity;
 import com.coffee.bus.entity.PatientDeviceRepeatDomain;
-import com.coffee.bus.entity.PatientMonitorDomain;
+import com.coffee.bus.service.dto.PatientMonitorResult;
 import com.coffee.bus.service.dto.PatientDeviceNoneResult;
 import com.coffee.bus.service.dto.PatientMonitorQuery;
 import org.apache.ibatis.annotations.Mapper;
@@ -39,5 +39,7 @@ public interface BusPatientMapper extends BaseMapper<BusPatientEntity> {
      * @param query
      * @return
      */
-    IPage<PatientMonitorDomain> selectMonitor(IPage<PatientMonitorDomain> page,@Param("query") PatientMonitorQuery query);
+    IPage<PatientMonitorResult> selectMonitor(IPage<PatientMonitorResult> page, @Param("query") PatientMonitorQuery query);
+
+    PatientMonitorResult findByPatientCode(@Param("tenantId") String tenantId,@Param("patientCode")String patientCode);
 }

+ 0 - 8
coffee-system/src/main/java/com/coffee/bus/registry/Operator.java

@@ -18,14 +18,6 @@ import java.util.*;
  * @createTime 2022年04月07日 16:07:00
  */
 public interface Operator<T> {
-    /**
-     * 获取所有缓存数据
-     * @return
-     */
-    @Deprecated
-    T get();
-
-    void set(T all);
 
     ConfigStorage getConfig();
 

+ 4 - 87
coffee-system/src/main/java/com/coffee/bus/registry/device/ClusterDeviceOperator.java

@@ -8,6 +8,7 @@ import com.coffee.bus.registry.device.bean.DeviceCacheInfo;
 import com.coffee.common.cache.ConfigStorage;
 import com.coffee.common.cache.value.Value;
 import lombok.AllArgsConstructor;
+import org.python.antlr.ast.Str;
 
 import java.util.Date;
 import java.util.*;
@@ -28,90 +29,6 @@ public class ClusterDeviceOperator implements DeviceOperator<DeviceCacheInfo> {
         return configStorage;
     }
 
-    @Override
-    public DeviceCacheInfo get() {
-//        Map<String, Value> result = configStorage.getKeys(getAllKeys());
-//        DeviceCacheInfo cacheInfo = DeviceCacheInfo.builder().build();
-//        Value deviceId =parseValue(result.get("deviceId")) ;
-//        if(deviceId!=null&&deviceId.get()!=null){
-//            cacheInfo.setDeviceId(deviceId.asString());
-//        }
-//        Value alias =parseValue(result.get("alias"));
-//        if(alias!=null&&alias.get()!=null){
-//            cacheInfo.setAlias(alias.asString());
-//        }
-//        Value enable =parseValue( result.get("enable"));
-//        if(enable!=null&&enable.get()!=null){
-//            cacheInfo.setEnable(enable.asBoolean());
-//        }
-//        Value tenantId =parseValue(result.get("tenantId")) ;
-//        if(tenantId!=null&&tenantId.get()!=null){
-//            cacheInfo.setTenantId(tenantId.asString());
-//        }
-//        Value usingId =parseValue(result.get("usingId")) ;
-//        if(usingId!=null&&usingId.get()!=null){
-//            cacheInfo.setUsingId(usingId.asString());
-//        }
-//        Value startTime = parseValue(result.get("startTime"));
-//        if(startTime!=null&&startTime.get()!=null){
-//            cacheInfo.setStartTime(startTime.asDate());
-//        }
-//        Value patientCode = parseValue(result.get("patientCode"));
-//        if(patientCode!=null&&patientCode.get()!=null){
-//            cacheInfo.setPatientCode(patientCode.asString());
-//        }
-//        Value status =parseValue( result.get("status"));
-//        if(status!=null&&status.get()!=null){
-//            cacheInfo.setStatus(status.as(DeviceStatusEnum.class));
-//        }
-//        Value master = parseValue(result.get("master"));
-//        if(master!=null&&master.get()!=null){
-//            cacheInfo.setMaster(master.asBoolean());
-//        }
-//        Value classification = parseValue(result.get("classification"));
-//        if(classification!=null&&classification.get()!=null){
-//            cacheInfo.setClassification(classification.asString());
-//        }
-//        return cacheInfo;
-        return null;
-    }
-
-    @Override
-    public void set(DeviceCacheInfo all) {
-        Map<String, Object> map = new HashMap<>();
-        if(StrUtil.isNotEmpty(all.getDeviceId())){
-            map.put("deviceId",all.getDeviceId());
-        }
-        if(StrUtil.isNotEmpty(all.getAlias())){
-            map.put("alias",all.getAlias());
-        }
-        if(all.getEnable()!=null){
-            map.put("enable",all.getEnable());
-        }
-        if(StrUtil.isNotEmpty(all.getTenantId())){
-            map.put("tenantId",all.getTenantId());
-        }
-        if(StrUtil.isNotEmpty(all.getUsingId())){
-            map.put("usingId",all.getUsingId());
-        }
-        if(all.getStartTime()!=null){
-            map.put("startTime",all.getStartTime());
-        }
-        if(StrUtil.isNotEmpty(all.getPatientCode())){
-            map.put("patientCode",all.getPatientCode());
-        }
-        if(all.getStatus()!=null){
-            map.put("status",all.getStatus());
-        }
-        if(all.getMaster()!=null){
-            map.put("master",all.getMaster());
-        }
-        if(all.getClassification()!=null){
-            map.put("classification",all.getClassification());
-        }
-        configStorage.setConfigs(map);
-    }
-
     @Override
     public void setDeviceId(String deviceId) {
         configStorage.setConfig(DeviceKeyConstant.DEVICE_ID,deviceId);
@@ -208,13 +125,13 @@ public class ClusterDeviceOperator implements DeviceOperator<DeviceCacheInfo> {
     }
 
     @Override
-    public void setAlarm(DeviceAlarmEnum alarm) {
+    public void setAlarm(String alarm) {
         configStorage.setConfig(DeviceKeyConstant.ALARM,alarm);
     }
 
     @Override
-    public DeviceAlarmEnum getAlarm() {
-        return getValue(DeviceKeyConstant.ALARM).as(DeviceAlarmEnum.class);
+    public String getAlarm() {
+        return getValue(DeviceKeyConstant.ALARM).asString();
     }
 
     @Override

+ 4 - 1
coffee-system/src/main/java/com/coffee/bus/registry/device/ClusterDeviceRegistry.java

@@ -3,6 +3,7 @@ package com.coffee.bus.registry.device;
 import cn.hutool.core.util.StrUtil;
 import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
 import com.baomidou.mybatisplus.core.conditions.update.UpdateWrapper;
+import com.coffee.bus.entity.BusDeviceAlarmEntity;
 import com.coffee.bus.entity.BusDeviceEntity;
 import com.coffee.bus.entity.BusDeviceRunningEntity;
 import com.coffee.bus.entity.BusInfusionModifyEntity;
@@ -56,7 +57,6 @@ public class ClusterDeviceRegistry implements DeviceRegistry {
                 //设备运行信息
                 deviceOperator.setUsingId(runningInfo.getId());
                 deviceOperator.setClassification(runningInfo.getClassification());
-                deviceOperator.setAlarm(runningInfo.getAlarm());
                 deviceOperator.setAlias(runningInfo.getAlias());
                 deviceOperator.setUndo(runningInfo.getIsUndo());
                 if(StrUtil.isNotEmpty(runningInfo.getInfusionId())){
@@ -66,6 +66,9 @@ public class ClusterDeviceRegistry implements DeviceRegistry {
                         deviceOperator.setInfusionParam(infusionModify.signParam(DeviceInfoListener.sign));
                     }
                 }
+                if (BusDeviceAlarmEntity.alarmOrWarn(runningInfo)) {
+                    deviceOperator.setAlarm(BusDeviceAlarmEntity.parseRunning(runningInfo).signParm(DeviceInfoListener.sign));
+                }
                 deviceOperator.setMaster(runningInfo.getMaster());
                 deviceOperator.setStartTime(runningInfo.getStartTime());
                 deviceOperator.setStatus(runningInfo.getRunState());

+ 2 - 2
coffee-system/src/main/java/com/coffee/bus/registry/device/DeviceOperator.java

@@ -142,13 +142,13 @@ public interface DeviceOperator<T> extends Operator<T> {
      * 设置当前设备报警信息
      * @param alarm
      */
-    void setAlarm(DeviceAlarmEnum alarm);
+    void setAlarm(String alarm);
 
     /**
      * 获取当前设备报警信息
      * @return
      */
-    DeviceAlarmEnum getAlarm();
+    String getAlarm();
 
     /**
      * 设置当前设备输注参数

+ 18 - 81
coffee-system/src/main/java/com/coffee/bus/registry/patient/ClusterPatientOperator.java

@@ -1,15 +1,15 @@
 package com.coffee.bus.registry.patient;
 
 import cn.hutool.core.collection.CollectionUtil;
-import cn.hutool.core.util.StrUtil;
+import cn.hutool.json.JSONUtil;
 import com.coffee.bus.registry.constant.PatientKeyConstant;
 import com.coffee.bus.registry.patient.bean.DeviceTimeSmallInfo;
 import com.coffee.bus.registry.patient.bean.PatientCacheInfo;
 import com.coffee.common.cache.ConfigStorage;
 import com.coffee.common.enums.SexEnum;
-import lombok.AllArgsConstructor;
 
 import java.util.*;
+import java.util.stream.Collectors;
 
 /**
  * @author lifang
@@ -18,90 +18,16 @@ import java.util.*;
  * @Description 病号操作符
  * @createTime 2022年04月07日 15:25:00
  */
-@AllArgsConstructor
 public class ClusterPatientOperator implements PatientOperator<PatientCacheInfo> {
     private final ConfigStorage configStorage;
 
-    @Override
-    public ConfigStorage getConfig() {
-        return configStorage;
+    public ClusterPatientOperator(ConfigStorage configStorage) {
+        this.configStorage = configStorage;
     }
 
     @Override
-    public PatientCacheInfo get() {
-//        Map<String, Value> result = configStorage.getKeys(getAllKeys());
-//        PatientCacheInfo cacheInfo = PatientCacheInfo.builder().build();
-//        Value code =parseValue(result.get("code")) ;
-//        if(code!=null&&code.get()!=null){
-//            cacheInfo.setCode(code.asString());
-//        }
-//        Value gender =parseValue(result.get("gender"));
-//        if(gender!=null&&gender.get()!=null){
-//            cacheInfo.setGender(gender.as(SexEnum.class));
-//        }
-//        Value name =parseValue( result.get("name"));
-//        if(name!=null&&name.get()!=null){
-//            cacheInfo.setName(name.asString());
-//        }
-//        Value tenantId =parseValue(result.get("tenantId")) ;
-//        if(tenantId!=null&&tenantId.get()!=null){
-//            cacheInfo.setTenantId(tenantId.asString());
-//        }
-//        Value clinicId =parseValue(result.get("clinicId")) ;
-//        if(clinicId!=null&&clinicId.get()!=null){
-//            cacheInfo.setClinicId(clinicId.asString());
-//        }
-//        Value startTime = parseValue(result.get("startTime"));
-//        if(startTime!=null&&startTime.get()!=null){
-//            cacheInfo.setStartTime(startTime.asDate());
-//        }
-//        Value finished = parseValue(result.get("finished"));
-//        if(finished!=null&&finished.get()!=null){
-//            cacheInfo.setFinished(finished.asBoolean());
-//        }
-//        Value bindDeviceId =parseValue( result.get("bindDeviceId"));
-//        if(bindDeviceId!=null&&bindDeviceId.get()!=null){
-//            cacheInfo.setBindDeviceId(bindDeviceId.asString());
-//        }
-//        Value devices = parseValue(result.get("devices"));
-//        if(devices!=null&&devices.get()!=null){
-//            cacheInfo.setDevices(code.as(HashSet.class));
-//        }
-        return null;
-    }
-
-    @Override
-    public void set(PatientCacheInfo all) {
-        Map<String, Object> map = new HashMap<>();
-        if(StrUtil.isNotEmpty(all.getCode())){
-            map.put("code",all.getCode());
-        }
-        if(all.getGender()!=null){
-            map.put("gender",all.getGender().ordinal());
-        }
-        if(StrUtil.isNotEmpty(all.getName())){
-            map.put("name",all.getName());
-        }
-        if(StrUtil.isNotEmpty(all.getTenantId())){
-            map.put("tenantId",all.getTenantId());
-        }
-        if(StrUtil.isNotEmpty(all.getClinicId())){
-            map.put("clinicId",all.getClinicId());
-        }
-        if(all.getStartTime()!=null){
-            map.put("startTime",all.getStartTime());
-        }
-        if(all.getIsFinished()!=null){
-            map.put("finished",all.getIsFinished());
-        }
-        if(StrUtil.isNotEmpty(all.getBindDeviceId())){
-            map.put("bindDeviceId",all.getBindDeviceId());
-        }
-        if(CollectionUtil.isNotEmpty(all.getDevices())){
-            map.put("devices",all.getDevices());
-        }
-        configStorage.setConfigs(map);
-
+    public ConfigStorage getConfig() {
+        return configStorage;
     }
 
 
@@ -212,7 +138,14 @@ public class ClusterPatientOperator implements PatientOperator<PatientCacheInfo>
 
     @Override
     public Set<DeviceTimeSmallInfo> getAllDevice() {
-        return getValue(PatientKeyConstant.DEVICES).as(HashSet.class);
+        Set<Map<String,Object>> set = getValue(PatientKeyConstant.DEVICES).as(HashSet.class);
+        if(CollectionUtil.isNotEmpty(set)){
+            return set.stream()
+                    .map(JSONUtil::toJsonStr)
+                    .map(json-> JSONUtil.toBean(json,DeviceTimeSmallInfo.class))
+                    .collect(Collectors.toSet());
+        }
+        return new HashSet<>();
     }
 
     @Override
@@ -246,4 +179,8 @@ public class ClusterPatientOperator implements PatientOperator<PatientCacheInfo>
     public List<String> getAllKeys(){
         return Arrays.asList("code","gender","name","tenantId","clinicId","startTime","finished","bindDeviceId","devices");
     }
+
+    //该病人是否为新增病人
+    private boolean newPatient;
+
 }

+ 63 - 27
coffee-system/src/main/java/com/coffee/bus/registry/patient/ClusterPatientRegistry.java

@@ -1,23 +1,31 @@
 package com.coffee.bus.registry.patient;
 
+import cn.hutool.core.collection.CollectionUtil;
 import cn.hutool.core.util.StrUtil;
 import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
+import com.baomidou.mybatisplus.core.toolkit.IdWorker;
 import com.coffee.bus.entity.BusClinicEntity;
+import com.coffee.bus.entity.BusDeviceRunningEntity;
 import com.coffee.bus.entity.BusInfusionHistoryEntity;
 import com.coffee.bus.entity.BusPatientEntity;
 import com.coffee.bus.registry.RegistryConstant;
+import com.coffee.bus.registry.patient.bean.DeviceTimeSmallInfo;
 import com.coffee.bus.registry.patient.bean.PatientCacheInfo;
 import com.coffee.bus.service.LocalBusClinicService;
+import com.coffee.bus.service.LocalBusDeviceRunningService;
 import com.coffee.bus.service.LocalBusInfusionHistoryService;
 import com.coffee.bus.service.LocalBusPatientService;
 import com.coffee.common.cache.manager.ClusterConfigStorageManager;
+import com.coffee.common.cache.value.Value;
 import lombok.AllArgsConstructor;
 import lombok.extern.slf4j.Slf4j;
 import org.springframework.dao.DuplicateKeyException;
 import org.springframework.stereotype.Service;
 import org.springframework.transaction.annotation.Transactional;
 
-import java.util.Map;
+import java.util.*;
+import java.util.stream.Collectors;
+
 
 /**
  * @author lifang
@@ -34,14 +42,22 @@ public class ClusterPatientRegistry implements PatientRegistry {
     private final ClusterConfigStorageManager configStorageManager;
     private final LocalBusClinicService clinicService;
     private final LocalBusInfusionHistoryService infusionService;
+    private final LocalBusDeviceRunningService deviceRunningService;
+
     @Override
     @Transactional(rollbackFor = Exception.class)
-    public PatientOperator<PatientCacheInfo> getOperator(String hospitalId, String patientCode) {
+    public PatientOperator<PatientCacheInfo> getOperator(String hospitalId, String patientCode){
+        return this.getOperator(hospitalId,patientCode,new HashMap<>());
+    }
+
+    @Override
+    @Transactional(rollbackFor = Exception.class)
+    public PatientOperator<PatientCacheInfo> getOperator(String hospitalId, String patientCode, Map<String, Object> params) {
         if(StrUtil.isEmpty(hospitalId)||StrUtil.isEmpty(patientCode)){
             return null;
         }
         String key=getId()+hospitalId+":"+patientCode;
-        ClusterPatientOperator patientOperator = new ClusterPatientOperator( configStorageManager.getStorage(key));
+        ClusterPatientOperator patientOperator = new ClusterPatientOperator(configStorageManager.getStorage(key));
         String code = patientOperator.getCode();
         if(StrUtil.isNullOrUndefined(code)){
             //将新数据存入数据库
@@ -50,51 +66,71 @@ public class ClusterPatientRegistry implements PatientRegistry {
                     .lambda().eq(BusPatientEntity::getCode, patientCode)
                     .eq(BusPatientEntity::getTenantId, hospitalId));
             boolean insert=false;
+            BusClinicEntity clinic=new BusClinicEntity();
             if(patient==null){
+                clinic.setId(IdWorker.getIdStr());
+                clinic.setPatientCode(patientCode);
+                clinic.setTenantId(hospitalId);
+                clinic.setMonitorType(true);
+                clinic.setMonitorStartTime(Value.simple(params.get("startTime")).asDate());
+                //当用户不存在时,创建用户,并给与用户一个空的临床信息
                 insert=true;
                 patient=new BusPatientEntity();
                 patient.setCode(patientCode);
-                //默认为空字符串
-                patient.setClinicId("");
                 patient.setTenantId(hospitalId);
+                //异步拉取his信息
+                clinicService.asyncFromHis(hospitalId,patientCode);
+            }else {
+                clinic = clinicService.recentClinicByPatientCode(hospitalId, patientCode);
             }
+
             patientOperator.setCode(patientCode);
             patientOperator.setTenantId(hospitalId);
             patientOperator.setName(patient.getName());
             patientOperator.setGender(patient.getGender());
 
-            BusClinicEntity clinic = clinicService.recentClinicByPatientCode(hospitalId, patientCode);
-            //不存在临床或临床已结束
-            if(clinic==null||Boolean.TRUE.equals(clinic.getFinished())){
-                clinicService.asyncFromHis(hospitalId,patientCode);
-                patient.setClinicId("-1");
-                patientOperator.setClinicId("-1");
-            }else {
-                //填充临床信息
-                patient.setName(clinic.getName());
-                patient.setTmpFinished(clinic.getFinished());
-                patient.setClinicId(clinic.getId());
-                patient.setTmpFinished(clinic.getFinished());
+            //填充临床信息
+            patient.setName(clinic.getName());
+            patient.setClinicId(clinic.getId());
 
-                patientOperator.setWard(clinic.getWard());
-                patientOperator.setBedNo(clinic.getBedNo());
-                patientOperator.setClinicId(clinic.getId());
-                patientOperator.setFinished(clinic.getFinished());
-            }
+            patientOperator.setWard(clinic.getWard());
+            patientOperator.setBedNo(clinic.getBedNo());
+            patientOperator.setClinicId(clinic.getId());
+            patientOperator.setFinished(clinic.getFinished());
             //填充输注信息
-            BusInfusionHistoryEntity infusion = infusionService.recentInfusionByPatientCode(hospitalId, patientCode);
-            if(infusion!=null){
-                patient.setInfusionId(infusion.getId());
-                patient.setMonitorStartTime(infusion.getStartTime());
-                patient.setMonitorEndTime(infusion.getUndoTime());
+            BusInfusionHistoryEntity recentInfusion = infusionService.recentInfusionByPatientCode(hospitalId, patientCode);
+            if(recentInfusion!=null){
+                patient.setInfusionId(recentInfusion.getId());
+                clinic.setMonitorStartTime(recentInfusion.getStartTime());
+                //监护已结束
+                if(Boolean.TRUE.equals(recentInfusion.getIsUndo())){
+                    clinic.setEndTime(recentInfusion.getUndoTime());
+                    clinic.setFinished(true);
+                }
+            }
+            //填充主副泵信息
+            List<BusDeviceRunningEntity> runningList = deviceRunningService.list(new QueryWrapper<BusDeviceRunningEntity>().lambda().eq(BusDeviceRunningEntity::getPatientCode, patientCode).eq(BusDeviceRunningEntity::getTenantId, hospitalId));
+            if (CollectionUtil.isNotEmpty(runningList)) {
+                Set<DeviceTimeSmallInfo> allDevice = runningList.stream().map(running ->
+                        DeviceTimeSmallInfo.of(running.getDeviceId(), running.getStartTime())
+                )
+                        .collect(Collectors.toSet());
+                Optional<BusDeviceRunningEntity> first = runningList.stream().filter(running -> Boolean.TRUE.equals(running.getMaster())).findFirst();
+                if(first.isPresent()){
+                    patientOperator.setBindDeviceId(first.get().getDeviceId());
+                }
+                patientOperator.setAllDevice(allDevice);
             }
             if(insert){
                 try {
                     log.info("医院[{}]新增病号数据[{}]",hospitalId,patientCode);
                     patientService.save(patient);
+                    clinicService.save(clinic);
                 }catch (DuplicateKeyException e){
                     log.warn("病号重复插入,医院id:[{}],病号:[{}]",hospitalId,patientCode);
                 }
+            }else {
+                clinicService.updateById(clinic);
             }
         }
         return patientOperator;

+ 0 - 2
coffee-system/src/main/java/com/coffee/bus/registry/patient/PatientOperator.java

@@ -165,6 +165,4 @@ public interface PatientOperator<T> extends Operator<T> {
      * 情空病号泵信息
      */
     void clearDevice();
-
-
 }

+ 6 - 0
coffee-system/src/main/java/com/coffee/bus/registry/patient/PatientRegistry.java

@@ -2,6 +2,9 @@ package com.coffee.bus.registry.patient;
 
 import com.coffee.bus.registry.Registry;
 import com.coffee.bus.registry.patient.bean.PatientCacheInfo;
+import org.springframework.transaction.annotation.Transactional;
+
+import java.util.Map;
 
 /**
  * @author lifang
@@ -19,6 +22,9 @@ public interface PatientRegistry extends Registry {
      */
     PatientOperator<PatientCacheInfo> getOperator(String hospitalId, String patientCode);
 
+
+    PatientOperator<PatientCacheInfo> getOperator(String hospitalId, String patientCode, Map<String, Object> params);
+
     /**
      * 删除病人信息
      * @param hospitalId

+ 2 - 10
coffee-system/src/main/java/com/coffee/bus/script/ScriptManager.java

@@ -1,17 +1,8 @@
 package com.coffee.bus.script;
 
-import cn.hutool.core.bean.BeanUtil;
 import cn.hutool.core.collection.CollectionUtil;
-import cn.hutool.core.util.ObjectUtil;
-import cn.hutool.core.util.StrUtil;
-import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
-import com.coffee.bus.bean.Script;
-import com.coffee.bus.entity.BusHospitalEntity;
 import com.coffee.bus.service.LocalBusHospitalService;
-import lombok.AllArgsConstructor;
-import org.springframework.beans.factory.annotation.Autowired;
 import org.springframework.boot.CommandLineRunner;
-import org.springframework.context.annotation.Configuration;
 import org.springframework.stereotype.Component;
 
 import javax.annotation.PostConstruct;
@@ -51,7 +42,8 @@ public class ScriptManager implements CommandLineRunner {
     public ScriptParse getById(String id){
         ScriptParse scriptParse = scriptParseMap.get(id);
         if(scriptParse==null){
-            throw new RuntimeException("不支持解析[{"+id+"}]脚本");
+//            throw new RuntimeException("不支持解析[{"+id+"}]脚本");
+            return new DefaultParse();
         }
         return scriptParse;
     }

+ 142 - 14
coffee-system/src/main/java/com/coffee/bus/service/LocalBusClinicService.java

@@ -1,14 +1,25 @@
 package com.coffee.bus.service;
 
 import cn.hutool.core.collection.CollectionUtil;
+import cn.hutool.core.util.StrUtil;
+import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
 import com.baomidou.mybatisplus.core.conditions.update.UpdateWrapper;
+import com.baomidou.mybatisplus.core.metadata.IPage;
+import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
 import com.coffee.bus.controller.vo.ClinicStatsVo;
 import com.coffee.bus.entity.BusClinicEntity;
+import com.coffee.bus.entity.BusDeviceRunningEntity;
+import com.coffee.bus.entity.BusInfusionHistoryEntity;
 import com.coffee.bus.entity.BusPatientEntity;
 import com.coffee.bus.mapper.BusClinicMapper;
+import com.coffee.bus.registry.patient.PatientOperator;
 import com.coffee.bus.registry.patient.PatientRegistry;
+import com.coffee.bus.registry.patient.bean.PatientCacheInfo;
+import com.coffee.bus.service.dto.ClinicQuery;
+import com.coffee.bus.service.dto.ClinicResult;
 import com.coffee.bus.service.dto.ClinicStatsQueryResult;
 import com.coffee.bus.service.dto.ClinicStatsReturnResult;
+import com.coffee.bus.utils.WsPublishUtils;
 import com.coffee.common.crud.BaseService;
 import lombok.extern.slf4j.Slf4j;
 import org.springframework.beans.factory.annotation.Autowired;
@@ -16,7 +27,10 @@ import org.springframework.context.annotation.Lazy;
 import org.springframework.scheduling.annotation.Async;
 import org.springframework.stereotype.Service;
 import org.springframework.transaction.annotation.Transactional;
+import org.springframework.util.Assert;
+
 import java.util.*;
+import java.util.function.Supplier;
 
 /**
  * @author lifang
@@ -28,12 +42,21 @@ import java.util.*;
 @Service
 @Slf4j
 public class LocalBusClinicService extends BaseService<BusClinicMapper, BusClinicEntity,String> {
+    @Autowired
+    @Lazy
+    private PatientRegistry patientRegistry;
+    @Autowired
+    @Lazy
+    private LocalBusInfusionHistoryService infusionHistoryService;
+    @Autowired
+    @Lazy
+    private LocalBusDeviceRunningService deviceRunningService;
     @Autowired
     @Lazy
     private LocalBusPatientService patientService;
     @Autowired
     @Lazy
-    private PatientRegistry patientRegistry;
+    private WsPublishUtils wsPublishUtils;
     @Override
     public void validateBeforeSave(BusClinicEntity entity) {
 
@@ -56,32 +79,29 @@ public class LocalBusClinicService extends BaseService<BusClinicMapper, BusClini
 
     /**
      * 结束当前医院病号的临床数据
-     * @param patientCodes 病号
+     * @param clinicId 临床id
      */
     @Transactional(rollbackFor = Exception.class)
-    public void finish(List<String> patientCodes, String tenantId) {
-        this.finish(patientCodes,new Date(),tenantId);
+    public void finish(String clinicId, String tenantId) {
+        this.finish(Collections.singletonList(clinicId),new Date(),tenantId);
     }
 
     /**
      * 结束当前医院病号的临床数据
-     * @param patientCodes 病号
+     * @param clinicIds 临床id
      * @param  finishTime 临床结束时间
      */
     @Transactional(rollbackFor = Exception.class)
-    public void finish(List<String> patientCodes,Date finishTime, String tenantId) {
+    public void finish(List<String> clinicIds,Date finishTime, String tenantId) {
         this.update(new UpdateWrapper<BusClinicEntity>().lambda()
-                .in(BusClinicEntity::getPatientCode,patientCodes)
-                .eq(BusClinicEntity::getFinished,false)
+                .in(BusClinicEntity::getId,clinicIds)
                 .set(BusClinicEntity::getFinished,true)
                 .set(BusClinicEntity::getEndTime,finishTime));
-
-        patientService.update(new UpdateWrapper<BusPatientEntity>().lambda()
-                .in(BusPatientEntity::getCode,patientCodes)
-                .set(BusPatientEntity::getTmpFinished,true)
-                .set(BusPatientEntity::getMonitorEndTime,finishTime));
         //更新病人缓存
-        patientCodes.stream().map(code->patientRegistry.getOperator(tenantId,code)).forEach(operator->operator.setFinished(true));
+        this.listByIds(clinicIds).stream()
+                .map(BusClinicEntity::getPatientCode)
+                .map(code->patientRegistry.getOperator(tenantId,code))
+                .forEach(operator->operator.setFinished(true));
     }
 
     /**
@@ -93,6 +113,110 @@ public class LocalBusClinicService extends BaseService<BusClinicMapper, BusClini
         return this.baseMapper.recentClinic(hospitalId,patientCode);
     }
 
+    /**
+     * 描述: 对两场手术进行比较,判断名称、时间是否发生了变化
+     * @author lifang
+     * @date 2022/5/12 9:10
+     * @param source his系统拉取的数据
+     * @param target 数据库存储的数据
+     * @return void
+     */
+    @Transactional(rollbackFor = Exception.class)
+    public void compareFromHis(BusClinicEntity source,BusClinicEntity target){
+        Assert.hasText(target.getId(),"LocalBusClinicService.compareFromHis方法调用时,target参数id不能为空");
+        Assert.hasText(source.getPatientCode(),"LocalBusClinicService.compareFromHis方法调用时,source参数patientCode不能为空");
+        Assert.notNull(source.getStartTime(),"LocalBusClinicService.compareFromHis方法调用时,source参数startTime不能为空");
+        Assert.hasText(source.getName(),"LocalBusClinicService.compareFromHis方法调用时,source参数name不能为空");
+        source.setId(target.getId());
+        this.updateById(source);
+        //手术开始时间发生变化,重新计算输注数据
+        if(source.getStartTime()!=null&&source.getStartTime()!=target.getStartTime()){
+            infusionHistoryService.adjustInfusionByClinic(source.getId(),source.getPatientCode(),source.getTenantId(),source.getStartTime());
+        }
+    }
+
+
+
+    /**
+     * 描述: his拉取的新的手术信息,执行插入操作
+     * @author lifang
+     * @date 2022/5/12 10:27
+     * @param source
+     * @return void
+     */
+    @Transactional(rollbackFor = Exception.class)
+    public void insertFromHis(BusClinicEntity source){
+        Assert.hasText(source.getTenantId(),"LocalBusClinicService.insertFromHis方法调用时,source参数tenantId不能为空");
+        Assert.hasText(source.getPatientCode(),"LocalBusClinicService.insertFromHis方法调用时,source参数patientCode不能为空");
+        Assert.hasText(source.getName(),"LocalBusClinicService.insertFromHis方法调用时,source参数name不能为空");
+        this.update(new UpdateWrapper<BusClinicEntity>()
+                .lambda()
+                .eq(BusClinicEntity::getPatientCode,source.getPatientCode()).eq(BusClinicEntity::getTenantId,source.getTenantId())
+                .eq(BusClinicEntity::getMonitorType,true)
+                .set(BusClinicEntity::getFinished,true));
+        this.save(source);
+        infusionHistoryService.adjustInfusionByClinic(source.getId(),source.getPatientCode(),source.getTenantId(),source.getStartTime());
+    }
+
+
+    /**
+     * 描述: 从his拉去的数据设置为当前临床信息
+     * @author lifang
+     * @date 2022/5/12 10:31
+     * @param source
+     * @return void
+     */
+    @Transactional(rollbackFor = Exception.class)
+    public void setCurrentClinicByHis(BusClinicEntity source){
+        Assert.hasText(source.getId(),"LocalBusClinicService.setCurrentClinic方法调用时,source参数id不能为空");
+        Assert.hasText(source.getPatientCode(),"LocalBusClinicService.setCurrentClinic方法调用时,source参数patientCode不能为空");
+        Assert.hasText(source.getTenantId(),"LocalBusClinicService.setCurrentClinic方法调用时,source参数tenantId不能为空");
+        Assert.notNull(source.getStartTime(),"LocalBusClinicService.setCurrentClinic方法调用时,source参数startTime不能为空");
+        //处理当前运行的信息
+        deviceRunningService.update(new UpdateWrapper<BusDeviceRunningEntity>().lambda()
+                .eq(BusDeviceRunningEntity::getPatientCode,source.getPatientCode())
+                .eq(BusDeviceRunningEntity::getTenantId,source.getTenantId())
+                .set(BusDeviceRunningEntity::getClinicId,source.getId()));
+
+        //处理当前的输注信息
+        infusionHistoryService.update(new UpdateWrapper<BusInfusionHistoryEntity>().lambda()
+                .eq(BusInfusionHistoryEntity::getPatientCode,source.getPatientCode())
+                .eq(BusInfusionHistoryEntity::getTenantId,source.getTenantId())
+                .eq(BusInfusionHistoryEntity::getFinished,false)
+                .set(BusInfusionHistoryEntity::getClinicId,source.getId()));
+
+        //更新病人信息
+        patientService.update(new UpdateWrapper<BusPatientEntity>().lambda()
+                .eq(BusPatientEntity::getCode,source.getPatientCode())
+                .eq(BusPatientEntity::getTenantId,source.getTenantId())
+                .set(BusPatientEntity::getClinicId,source.getId()));
+        //处理
+        List<BusClinicEntity> clinics = this.list(new QueryWrapper<BusClinicEntity>().lambda()
+                .eq(BusClinicEntity::getPatientCode, source.getPatientCode())
+                .eq(BusClinicEntity::getTenantId, source.getTenantId())
+                .eq(BusClinicEntity::getFinished, false)
+                .ne(BusClinicEntity::getId, source.getId()));
+        //将下一场手术的开始时间作为该场手术监控的结束时间
+        clinics.sort(Comparator.comparing(BusClinicEntity::getStartTime));
+        for (int i = 0; i < clinics.size(); i++) {
+            BusClinicEntity clinic = clinics.get(i);
+            clinic.setFinished(true);
+            if(i==clinics.size()-1){
+                if(clinic.getEndTime()==null){
+                    clinic.setEndTime(source.getEndTime());
+                }
+                continue;
+            }
+            if(clinic.getEndTime()==null){
+                clinic.setEndTime(clinics.get(i+1).getStartTime());
+            }
+        }
+        this.updateBatchById(clinics);
+
+        PatientOperator<PatientCacheInfo> operator = patientRegistry.getOperator(source.getTenantId(), source.getPatientCode());
+        operator.setClinicId(source.getId());
+        wsPublishUtils.publishPatientMonitor(source.getPatientCode(),source.getTenantId());
+    }
     /**
      * 从his同步病人数据-异步
      * @param hospitalId
@@ -106,4 +230,8 @@ public class LocalBusClinicService extends BaseService<BusClinicMapper, BusClini
     public ClinicStatsReturnResult stats(ClinicStatsVo statsVo) {
         return ClinicStatsReturnResult.of(this.baseMapper.stats(statsVo));
     }
+
+    public IPage<ClinicResult> pageQuery(ClinicQuery query){
+        return this.baseMapper.pageQuery(query.getPage(),query);
+    }
 }

+ 6 - 48
coffee-system/src/main/java/com/coffee/bus/service/LocalBusDeviceAlarmService.java

@@ -1,24 +1,17 @@
 package com.coffee.bus.service;
 
 import cn.hutool.core.util.StrUtil;
-import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
 import com.baomidou.mybatisplus.core.conditions.update.UpdateWrapper;
-import com.coffee.bus.controller.vo.DeviceUse;
+import com.baomidou.mybatisplus.core.metadata.IPage;
+import com.coffee.bus.entity.BusClinicEntity;
 import com.coffee.bus.entity.BusDeviceAlarmEntity;
-import com.coffee.bus.entity.BusHospitalEntity;
-import com.coffee.bus.enums.DeviceAlarmEnum;
 import com.coffee.bus.mapper.BusDeviceAlarmMapper;
-import com.coffee.bus.mapper.BusHospitalMapper;
+import com.coffee.bus.service.dto.AlarmQuery;
 import com.coffee.common.crud.BaseService;
 import lombok.AllArgsConstructor;
 import org.springframework.stereotype.Service;
 import org.springframework.transaction.annotation.Transactional;
 
-import java.util.ArrayList;
-import java.util.HashMap;
-import java.util.List;
-import java.util.Map;
-
 /**
  * @author lifang
  * @version 1.0.0
@@ -29,9 +22,6 @@ import java.util.Map;
 @Service
 @AllArgsConstructor
 public class LocalBusDeviceAlarmService extends BaseService<BusDeviceAlarmMapper, BusDeviceAlarmEntity,String> {
-    private final BusDeviceAlarmMapper deviceAlarmMapper;
-    private final BusHospitalMapper hospitalMapper;
-
     @Override
     public void validateBeforeSave(BusDeviceAlarmEntity entity) {
 
@@ -47,7 +37,9 @@ public class LocalBusDeviceAlarmService extends BaseService<BusDeviceAlarmMapper
 
     }
 
-
+    public IPage<BusDeviceAlarmEntity> pageQuery(AlarmQuery query){
+        return this.baseMapper.pageQuery(query.getPage(),query);
+    }
     /**
      * 添加报警原因
      * @param id
@@ -64,38 +56,4 @@ public class LocalBusDeviceAlarmService extends BaseService<BusDeviceAlarmMapper
         }
         this.update(new UpdateWrapper<BusDeviceAlarmEntity>().lambda().eq(BusDeviceAlarmEntity::getId,id).set(BusDeviceAlarmEntity::getCause,cause));
     }
-
-    /**
-     * 查看报警数量
-     */
-    @Transactional(rollbackFor = Exception.class)
-    public List<DeviceUse> countAlarm(){
-        List<BusHospitalEntity> hospitalList = hospitalMapper.selectList(new QueryWrapper<>());
-        List<DeviceUse> deviceUseList = new ArrayList<>();
-
-        for (BusHospitalEntity hospital:
-             hospitalList) {
-            DeviceUse deviceUse = new DeviceUse();
-            deviceUse.setName(hospital.getName());
-            deviceUse.setAddress(hospital.getAddress());
-            Map<DeviceAlarmEnum, Long> deviceAlarms = new HashMap<>();
-            deviceUse.setDeviceAlarms(deviceAlarms);
-
-            QueryWrapper<BusDeviceAlarmEntity> busDeviceAlarmEntityQueryWrapper = new QueryWrapper<>();
-            BusDeviceAlarmEntity busDeviceAlarmEntity = new BusDeviceAlarmEntity();
-            busDeviceAlarmEntityQueryWrapper.setEntity(busDeviceAlarmEntity);
-            busDeviceAlarmEntity.setTenantId(hospital.getId());
-            for (DeviceAlarmEnum alarmEnum:
-                    DeviceAlarmEnum.values()) {
-                busDeviceAlarmEntity.setAlarm(alarmEnum);
-                deviceAlarms.put(alarmEnum,deviceAlarmMapper.selectCount(busDeviceAlarmEntityQueryWrapper));
-            }
-
-
-            deviceUseList.add(deviceUse);
-
-        }
-        return deviceUseList;
-
-    }
 }

+ 9 - 0
coffee-system/src/main/java/com/coffee/bus/service/LocalBusDeviceHistoryService.java

@@ -1,7 +1,11 @@
 package com.coffee.bus.service;
 
+import com.baomidou.mybatisplus.core.metadata.IPage;
+import com.coffee.bus.entity.BusDeviceAlarmEntity;
 import com.coffee.bus.entity.BusDeviceHistoryEntity;
 import com.coffee.bus.mapper.BusDeviceHistoryMapper;
+import com.coffee.bus.service.dto.AlarmQuery;
+import com.coffee.bus.service.dto.DeviceHistoryQuery;
 import com.coffee.common.crud.BaseService;
 import org.springframework.stereotype.Service;
 
@@ -28,4 +32,9 @@ public class LocalBusDeviceHistoryService extends BaseService<BusDeviceHistoryMa
     public void validateBeforeDelete(String id) {
 
     }
+
+
+    public IPage<BusDeviceHistoryEntity> pageQuery(DeviceHistoryQuery query){
+        return this.baseMapper.pageQuery(query.getPage(),query);
+    }
 }

+ 56 - 3
coffee-system/src/main/java/com/coffee/bus/service/LocalBusDeviceManualService.java

@@ -1,11 +1,20 @@
 package com.coffee.bus.service;
 
+import cn.hutool.core.util.StrUtil;
+import cn.hutool.json.JSONUtil;
+import com.alibaba.fastjson.JSON;
+import com.alibaba.fastjson.serializer.SerializerFeature;
+import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
+import com.baomidou.mybatisplus.core.conditions.update.UpdateWrapper;
+import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
+import com.coffee.bus.controller.vo.MonitorFinishedVo;
 import com.coffee.bus.entity.BusClinicEntity;
 import com.coffee.bus.entity.BusDeviceManualEntity;
 import com.coffee.bus.mapper.BusDeviceManualMapper;
 import com.coffee.bus.service.dto.ManualMonitorQuery;
 import com.coffee.bus.service.dto.ManualMonitorResult;
 import com.coffee.common.crud.BaseService;
+import com.coffee.common.exception.CustomException;
 import lombok.extern.slf4j.Slf4j;
 import org.springframework.beans.factory.annotation.Autowired;
 import org.springframework.context.annotation.Lazy;
@@ -41,6 +50,27 @@ public class LocalBusDeviceManualService extends BaseService<BusDeviceManualMapp
 
     }
 
+    /**
+     * 编辑其他监控信息
+     * @param manual
+     * @param clinic
+     */
+    @Transactional(rollbackFor = Exception.class)
+    public void edit(BusDeviceManualEntity manual, BusClinicEntity clinic) {
+        if(StrUtil.isEmpty(clinic.getId())){
+            throw new CustomException("请选择临床信息");
+        }
+        clinicService.updateById(clinic);
+        if(StrUtil.isEmpty(manual.getId())){
+            BusDeviceManualEntity one = this.getOne(new QueryWrapper<BusDeviceManualEntity>().lambda().eq(BusDeviceManualEntity::getClinicId, clinic.getId()).last("limit 1"));
+            if(one!=null){
+                throw new CustomException("设备信息id不可为空");
+            }
+            manual.setClinicId(clinic.getId());
+        }
+        this.saveOrUpdate(manual);
+    }
+
     /**
      * 新增其他监控信息
      * @param manual
@@ -49,13 +79,36 @@ public class LocalBusDeviceManualService extends BaseService<BusDeviceManualMapp
     @Transactional(rollbackFor = Exception.class)
     public void save(BusDeviceManualEntity manual, BusClinicEntity clinic) {
         //将临床设置为无泵监控临床
+        Date now = new Date();
         clinic.setMonitorType(false);
+        if(clinic.getMonitorStartTime()==null){
+            clinic.setMonitorStartTime(now);
+        }
         clinicService.save(clinic);
-        manual.setClinicId(clinic.getId());
-        this.save(manual);
+        if(manual!=null){
+            manual.setClinicId(clinic.getId());
+            this.save(manual);
+        }
     }
 
     public List<ManualMonitorResult> selectMonitor(ManualMonitorQuery query){
-        return this.baseMapper.selectMonitor(query);
+        Page<ManualMonitorResult> page = new Page<>(0, 500, false);
+        return this.baseMapper.selectMonitor(page,query).getRecords();
+    }
+
+    /**
+     * 描述: 结束监控
+     * @author lifang
+     * @date 2022/5/10 11:52
+     * @param vo
+     * @return void
+     */
+    @Transactional(rollbackFor = Exception.class)
+    public void finishedMonitor(MonitorFinishedVo vo) {
+        clinicService.update(new UpdateWrapper<BusClinicEntity>().lambda()
+                .in(BusClinicEntity::getId,vo.getClinicIds())
+                .set(BusClinicEntity::getFinished,true)
+                .set(BusClinicEntity::getEndTime,vo.getUndo().getUndoTime())
+                .set(BusClinicEntity::getUndoConfig, vo.getUndo(),"typeHandler = com.baomidou.mybatisplus.extension.handlers.FastjsonTypeHandler"));
     }
 }

+ 20 - 20
coffee-system/src/main/java/com/coffee/bus/service/LocalBusDeviceRunningService.java

@@ -1,6 +1,7 @@
 package com.coffee.bus.service;
 
 import cn.hutool.core.collection.CollectionUtil;
+import cn.hutool.core.util.StrUtil;
 import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
 import com.baomidou.mybatisplus.core.conditions.update.UpdateWrapper;
 import com.coffee.bus.entity.BusPatientEntity;
@@ -17,8 +18,8 @@ import com.coffee.bus.entity.BusClinicEntity;
 import com.coffee.bus.entity.BusDeviceRunningEntity;
 import com.coffee.bus.entity.BusInfusionHistoryEntity;
 import com.coffee.bus.mapper.BusDeviceRunningMapper;
+import com.coffee.bus.utils.WsPublishUtils;
 import com.coffee.common.crud.BaseService;
-import com.coffee.common.exception.CustomException;
 import org.springframework.beans.factory.annotation.Autowired;
 import org.springframework.context.annotation.Lazy;
 import org.springframework.stereotype.Service;
@@ -52,13 +53,9 @@ public class LocalBusDeviceRunningService extends BaseService<BusDeviceRunningMa
     @Lazy
     private DeviceRegistry deviceRegistry;
 
-    public LocalBusDeviceRunningService(LocalBusInfusionHistoryService infusionHistoryService, PatientRegistry patientRegistry,LocalBusPatientService patientService, LocalBusClinicService clinicService) {
-        this.infusionHistoryService = infusionHistoryService;
-        this.patientRegistry = patientRegistry;
-        this.patientService=patientService;
-        this.clinicService=clinicService;
-    }
-
+    @Autowired
+    @Lazy
+    private WsPublishUtils wsPublishUtils;
     @Override
     public void validateBeforeSave(BusDeviceRunningEntity entity) {
 
@@ -74,6 +71,19 @@ public class LocalBusDeviceRunningService extends BaseService<BusDeviceRunningMa
 
     }
 
+    /**
+     * 描述: 获取设备别名
+     * @author lifang
+     * @date 2022/5/16 17:32
+     * @param deviceId
+     * @return String
+     */
+    public String getAliasName(String deviceId){
+        if(StrUtil.isBlank(deviceId)){
+            return null;
+        }
+        return deviceRegistry.getOperator(deviceId).getAlias();
+    }
     /**
      * 批量撤泵
      * @param undoConfigs 批量撤泵配置
@@ -129,22 +139,11 @@ public class LocalBusDeviceRunningService extends BaseService<BusDeviceRunningMa
         }
         //结束临床
         if(finishClinic){
-            clinicService.finish(Collections.singletonList(manualUndoConfig.getPatientCode()),manualUndoConfig.getTenantId());
+            clinicService.finish(manualUndoConfig.getClinicId(),manualUndoConfig.getTenantId());
         }
 
     }
 
-    @Transactional(rollbackFor = Exception.class)
-    public void updateClinicInfo(List<String> deviceIds, BusClinicEntity clinic) {
-        this.update(new UpdateWrapper<BusDeviceRunningEntity>().lambda()
-                .in(BusDeviceRunningEntity::getDeviceId,deviceIds)
-                .set(BusDeviceRunningEntity::getClinicId,clinic.getId())
-                .set(BusDeviceRunningEntity::getPatientName,clinic.getPatientName())
-                .set(BusDeviceRunningEntity::getWard,clinic.getWard())
-                .set(BusDeviceRunningEntity::getPatientSex,clinic.getPatientGender())
-                .set(BusDeviceRunningEntity::getBedNo,clinic.getBedNo()));
-    }
-
     /**
      * 切换主泵
      * @param shiftConfig 切换配置
@@ -185,4 +184,5 @@ public class LocalBusDeviceRunningService extends BaseService<BusDeviceRunningMa
         masterOperator.setMaster(true);
         patientOperator.setBindDeviceId(shiftConfig.getMasterDeviceId());
     }
+
 }

+ 111 - 18
coffee-system/src/main/java/com/coffee/bus/service/LocalBusDeviceService.java

@@ -3,19 +3,30 @@ package com.coffee.bus.service;
 import cn.hutool.core.util.StrUtil;
 import com.aliyuncs.iot.model.v20180120.QueryDeviceDetailResponse;
 import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
+import com.baomidou.mybatisplus.core.conditions.update.UpdateWrapper;
+import com.baomidou.mybatisplus.core.metadata.IPage;
+import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
 import com.coffee.aliyun.sdk.AliyunIotSdk;
 import com.coffee.bus.bean.AliIotConfig;
+import com.coffee.bus.entity.BusHospitalEntity;
 import com.coffee.bus.registry.device.DeviceRegistry;
 import com.coffee.bus.entity.BusDeviceEntity;
 import com.coffee.bus.mapper.BusDeviceMapper;
 import com.coffee.bus.registry.device.DeviceOperator;
+import com.coffee.bus.service.dto.DeviceQuery;
+import com.coffee.bus.service.dto.DeviceResult;
 import com.coffee.common.crud.BaseService;
+import com.coffee.common.exception.CustomException;
 import lombok.extern.slf4j.Slf4j;
 import org.springframework.beans.factory.annotation.Autowired;
 import org.springframework.context.annotation.Lazy;
 import org.springframework.stereotype.Service;
+import org.springframework.transaction.annotation.Transactional;
 
+import java.util.List;
 import java.util.Objects;
+import java.util.concurrent.CompletableFuture;
+import java.util.concurrent.ExecutionException;
 import java.util.concurrent.atomic.AtomicReference;
 
 /**
@@ -39,9 +50,12 @@ public class LocalBusDeviceService extends BaseService<BusDeviceMapper, BusDevic
     @Autowired
     private AliyunIotSdk aliyunIotSdk;
 
+
     @Override
     public void validateBeforeSave(BusDeviceEntity entity) {
-
+       if(entity.getTenantId()==null){
+           entity.setTenantId("1");
+       }
     }
 
     @Override
@@ -98,33 +112,60 @@ public class LocalBusDeviceService extends BaseService<BusDeviceMapper, BusDevic
      * 根据deviceId更新设备在线状态
      * @param device
      */
-    public boolean updateByDeviceId(BusDeviceEntity device){
+    public boolean updateDevice(BusDeviceEntity device){
         return this.update(device,new QueryWrapper<BusDeviceEntity>().lambda()
                 .eq(BusDeviceEntity::getDeviceId,device.getDeviceId()));
     }
 
     /**
      * @author 龙三郎
-     * 添加设备
+     * 保存一个设备,系统中存在时就更新,不存在时则插入。
      * @param entity
      */
-    public boolean saveByDeviceId(BusDeviceEntity entity) {
+    public boolean saveDevice(BusDeviceEntity entity) {
         // 查询设备是否存在,无视逻辑删除
-        BusDeviceEntity old = deviceMapper.selectOneByDeviceId(entity.getDeviceId());
+        BusDeviceEntity device = deviceMapper.selectOneByDeviceId(entity.getDeviceId());
+        // 判断设备是否存在
+        boolean isExists = Objects.nonNull(device);
         // 设备存在,且处于删除状态,首先去掉逻辑删除标志 ?? 逻辑删除后设备数据是否不再接收
-        if (Objects.nonNull(old) && old.getIsDelete() == 1){
+        if (isExists && device.getIsDelete() == 1){
             deviceMapper.notDelete(entity.getDeviceId());
         }
         // 设备存在
-        if (Objects.nonNull(old)){
+        if (isExists){
             // 更新设备
-            return this.updateByDeviceId(entity);
+            return this.updateDevice(entity);
         }else {
             // 添加设备
             return this.save(entity);
         }
     }
 
+    /**
+     * @author 龙三郎
+     * 更新一个系统中现有的设备
+     * @param deviceId
+     */
+    public boolean updateDeviceByDeviceId(String deviceId) {
+        // 查询设备是否存在
+        BusDeviceEntity device = getByDeviceId(deviceId);
+        // 设备不存在直接退出
+        if (Objects.isNull(device)){
+            return false;
+        }
+        // 从阿里云物联网查询设备
+        QueryDeviceDetailResponse response = aliyunIotSdk.queryDeviceDetail(deviceId);
+        // 设备存在
+        if (response.getSuccess()){
+            // 更新设备参数
+            device.updateFields(response.getData());
+            // 更新设备
+            return this.updateDevice(device);
+        }else {
+            return false;
+        }
+    }
+
     /**
      * @author 龙三郎
      * 根据deviceId获取设备
@@ -144,36 +185,88 @@ public class LocalBusDeviceService extends BaseService<BusDeviceMapper, BusDevic
      * @param deviceId
      * @return
      */
-    public BusDeviceEntity add(String deviceId) {
+    public BusDeviceEntity addDevice(String deviceId) {
         BusDeviceEntity device = new BusDeviceEntity();
         device.setConfig(new AliIotConfig());
         // 从阿里云物联网查询设备
         QueryDeviceDetailResponse response = aliyunIotSdk.queryDeviceDetail(deviceId);
         // 设备存在
         if (response.getSuccess()){
-            device.setFields(response.getData());
+            device.updateFields(response.getData());
             // 存储设备
-            this.saveByDeviceId(device);
+            this.saveDevice(device);
             return device;
         }
         // 不存在返回null
         return null;
     }
 
+
+    public IPage<DeviceResult> pageQuery(Page<DeviceResult> page, DeviceQuery query){
+        return this.baseMapper.pageQuery(page,query);
+    }
     /**
      * @author 龙三郎
      * 从阿里云平台获取全部的设备,同步到系统数据库
      * @return
      */
-    public int syncDevice() {
+    public int syncAllDevice(){
+        Integer m = 0;
+        // 创建异步执行任务,有返回值
+        CompletableFuture<Integer> cf = CompletableFuture.supplyAsync(()->{
+            AtomicReference<Integer> n = new AtomicReference<>(0);
+            // 同步所有的设备
+            aliyunIotSdk.queryDevice().forEach(item ->{
+                BusDeviceEntity device = new BusDeviceEntity();
+                device.setConfig(new AliIotConfig());
+                // 更新设备属性
+                device.updateFields(item);
+                n.updateAndGet(v -> v + (this.saveDevice(device)?1:0));
+            });
+            return n.get();
+        });
+        //等待子任务执行完成
+        try {
+            m = cf.get();
+        }catch (Exception e){
+            throw new CustomException(e.getMessage());
+        }
+        return m;
+    }
+
+    /**
+     * @author 龙三郎
+     * 根据ids获取指定的设备,更新本地设备
+     * @return
+     */
+    public int syncDevice(List<String> ids) {
         AtomicReference<Integer> n = new AtomicReference<>(0);
-        aliyunIotSdk.queryDevice().forEach(item ->{
-            BusDeviceEntity device = new BusDeviceEntity();
-            device.setConfig(new AliIotConfig());
-            // 更新设备属性
-            device.setFields(item);
-            n.updateAndGet(v -> v + (this.saveByDeviceId(device)?1:0));
+        // ids不能为空
+        if (Objects.isNull(ids) || ids.size() <= 0){
+            throw new CustomException("设备id不能为空");
+        }
+        // 同步指定的设备
+        ids.forEach(id->{
+            n.updateAndGet(v -> v + (this.updateDeviceByDeviceId(id)?1:0));
         });
         return n.get();
     }
+
+    /**
+     * 描述: 设备医院换绑操作
+     * @author lifang
+     * @date 2022/5/8 21:34
+     * @param deviceIds 换绑的设备id
+     * @param afterTenantId 换绑之后的医院id
+     * @return void
+     */
+    @Transactional(rollbackFor = Exception.class)
+    public void shift(List<String> deviceIds, String afterTenantId) {
+        this.update(new UpdateWrapper<BusDeviceEntity>().lambda()
+                .in(BusDeviceEntity::getDeviceId,deviceIds)
+                .set(BusDeviceEntity::getTenantId,afterTenantId));
+        deviceIds.stream()
+                .map(deviceRegistry::getOperator)
+                .forEach(deviceOperator -> deviceOperator.setTenantId(afterTenantId));
+    }
 }

+ 7 - 0
coffee-system/src/main/java/com/coffee/bus/service/LocalBusEvaluationService.java

@@ -1,7 +1,9 @@
 package com.coffee.bus.service;
 
+import com.baomidou.mybatisplus.core.metadata.IPage;
 import com.coffee.bus.entity.BusEvaluationEntity;
 import com.coffee.bus.mapper.BusEvaluationMapper;
+import com.coffee.bus.service.dto.EvalQuery;
 import com.coffee.common.crud.BaseService;
 import org.springframework.stereotype.Service;
 
@@ -14,6 +16,11 @@ import org.springframework.stereotype.Service;
  */
 @Service
 public class LocalBusEvaluationService extends BaseService<BusEvaluationMapper, BusEvaluationEntity,String> {
+
+    public IPage<BusEvaluationEntity> pageQuery(EvalQuery query) {
+        return this.baseMapper.pageQuery(query.getPage(),query);
+    }
+
     @Override
     public void validateBeforeSave(BusEvaluationEntity entity) {
 

+ 51 - 16
coffee-system/src/main/java/com/coffee/bus/service/LocalBusHospitalService.java

@@ -1,19 +1,24 @@
 package com.coffee.bus.service;
 
 import cn.hutool.core.collection.CollectionUtil;
+import cn.hutool.core.util.ObjectUtil;
 import cn.hutool.core.util.StrUtil;
+import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
+import com.baomidou.mybatisplus.core.toolkit.IdWorker;
 import com.coffee.bus.entity.BusHospitalEntity;
+import com.coffee.bus.his.HisScriptSession;
+import com.coffee.bus.his.HisScriptSessionManager;
+import com.coffee.bus.his.strategy.HisStrategyEnum;
 import com.coffee.bus.mapper.BusHospitalMapper;
+import com.coffee.bus.utils.CodeUtils;
 import com.coffee.common.config.mybatis.GetNameInterface;
 import com.coffee.common.crud.BaseService;
 import com.coffee.common.exception.CustomException;
+import org.springframework.beans.factory.annotation.Autowired;
 import org.springframework.boot.CommandLineRunner;
+import org.springframework.context.annotation.Lazy;
 import org.springframework.stereotype.Service;
-
-import java.util.HashMap;
-import java.util.List;
-import java.util.Map;
-import java.util.stream.Collectors;
+import java.util.Optional;
 
 /**
  * @author lifang
@@ -24,10 +29,21 @@ import java.util.stream.Collectors;
  */
 @Service
 public class LocalBusHospitalService extends BaseService<BusHospitalMapper, BusHospitalEntity,String> implements CommandLineRunner, GetNameInterface<String,String> {
-    private static Map<String,String> hospitalMap=new HashMap<>();
+    @Autowired
+    @Lazy
+    private HisScriptSessionManager scriptSessionManager;
     @Override
     public void validateBeforeSave(BusHospitalEntity entity) {
-
+        long id = IdWorker.getId();
+        String name = entity.getName();
+        if(validateName(name)){
+            throw new CustomException(String.format("医院名称[%s]不可重复",entity.getName()));
+        }
+        if(entity.getStrategy()==null){
+            entity.setStrategy(HisStrategyEnum.ALL);
+        }
+        entity.setCode(CodeUtils.genInviteCode(id));
+        entity.setId(String.valueOf(id));
     }
 
     @Override
@@ -35,6 +51,15 @@ public class LocalBusHospitalService extends BaseService<BusHospitalMapper, BusH
         if("1".equals(entity.getId())){
             throw new CustomException("系统级医院,不可修改");
         }
+        BusHospitalEntity hospital = this.getById(entity.getName());
+        if(hospital==null){
+            return;
+        }
+        if (!ObjectUtil.equal(entity.getName(), hospital.getName())) {
+            if(validateName(entity.getName())){
+                throw new CustomException(String.format("医院名称[%s]不可重复",entity.getName()));
+            }
+        }
     }
 
     @Override
@@ -46,27 +71,24 @@ public class LocalBusHospitalService extends BaseService<BusHospitalMapper, BusH
 
     @Override
     public void postSave(BusHospitalEntity entity) {
-        hospitalMap.put(entity.getId(),entity.getName());
+        HisScriptSession hisScriptSession = scriptSessionManager.get(entity.getId());
+        hisScriptSession.refresh(entity);
     }
 
     @Override
     public void postUpdate(BusHospitalEntity entity) {
-        hospitalMap.put(entity.getId(),entity.getName());
+        HisScriptSession hisScriptSession = scriptSessionManager.get(entity.getId());
+        hisScriptSession.refresh(entity);
     }
 
     @Override
     public void postDelete(String id) {
-        hospitalMap.remove(id);
+        scriptSessionManager.unregister(id);
     }
 
     @Override
     public void run(String... args) {
         saveDefaultHospital();
-        List<BusHospitalEntity> hospitalList = this.list();
-        if(CollectionUtil.isNotEmpty(hospitalList)){
-            Map<String, List<BusHospitalEntity>> collect = hospitalList.stream().collect(Collectors.groupingBy(BusHospitalEntity::getId));
-            collect.forEach((k,v)->hospitalMap.put(k,v.get(0).getName()));
-        }
     }
 
 
@@ -75,9 +97,11 @@ public class LocalBusHospitalService extends BaseService<BusHospitalMapper, BusH
         if(StrUtil.isAllBlank(id)){
             return "";
         }
-        return hospitalMap.get(id);
+        HisScriptSession hisScriptSession = scriptSessionManager.get(id);
+        return Optional.ofNullable(hisScriptSession.getHospitalInfo()).orElse(new BusHospitalEntity()).getName();
     }
 
+
     private void saveDefaultHospital(){
         BusHospitalEntity hospital = new BusHospitalEntity();
         hospital.setId("1");
@@ -93,4 +117,15 @@ public class LocalBusHospitalService extends BaseService<BusHospitalMapper, BusH
 
         }
     }
+
+    /**
+     * 描述: 医院名称是否有效
+     * @author lifang
+     * @date 2022/5/12 15:42
+     * @param name
+     * @return boolean
+     */
+    public boolean validateName(String name){
+        return this.getOne(new QueryWrapper<BusHospitalEntity>().lambda().eq(BusHospitalEntity::getName,name).last("limit 1"))==null;
+    }
 }

+ 44 - 0
coffee-system/src/main/java/com/coffee/bus/service/LocalBusInfusionHistoryService.java

@@ -1,10 +1,13 @@
 package com.coffee.bus.service;
 
+import cn.hutool.core.collection.CollectionUtil;
 import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
 import cn.hutool.extra.spring.SpringUtil;
+import com.baomidou.mybatisplus.core.conditions.update.UpdateWrapper;
 import com.coffee.aliyun.utils.Constants;
 import com.coffee.aliyun.utils.Items;
 import com.coffee.aliyun.utils.PumpParams;
+import com.coffee.bus.entity.BusClinicEntity;
 import com.coffee.bus.entity.BusDeviceEntity;
 import com.coffee.bus.entity.BusInfusionHistoryEntity;
 import com.coffee.bus.entity.BusPatientEntity;
@@ -15,7 +18,12 @@ import com.coffee.common.crud.BaseService;
 import org.springframework.beans.factory.annotation.Autowired;
 import org.springframework.context.annotation.Lazy;
 import org.springframework.stereotype.Service;
+import org.springframework.transaction.annotation.Transactional;
+import org.springframework.util.Assert;
 
+import java.util.Comparator;
+import java.util.Date;
+import java.util.List;
 import java.util.Objects;
 
 /**
@@ -35,6 +43,10 @@ public class LocalBusInfusionHistoryService extends BaseService<BusInfusionHisto
     @Lazy
     private LocalBusPatientService patientService;
 
+    @Autowired
+    @Lazy
+    private LocalBusClinicService clinicService;
+
     @Override
     public void validateBeforeSave(BusInfusionHistoryEntity entity) {
 
@@ -125,4 +137,36 @@ public class LocalBusInfusionHistoryService extends BaseService<BusInfusionHisto
                 .lambda()
                 .eq(BusInfusionHistoryEntity::getTenantId,hospitalId).eq(BusInfusionHistoryEntity::getPatientCode,patientCode).last("limit 1"));
     }
+
+    /**
+     * 描述: 通过临床手术的开始时间调整输注信息所绑定的手术信息
+     * @author lifang
+     * @date 2022/5/12 9:28
+     * @param clinicId 手术id
+     * @param patientCode 病号
+     * @param tenantId 医院id
+     * @param startTime 开始时间
+     * @return void
+     */
+    @Transactional(rollbackFor = Exception.class)
+    public void adjustInfusionByClinic(String clinicId, String patientCode, String tenantId, Date startTime){
+        Assert.hasText(clinicId,"手术id不可为空");
+        Assert.hasText(patientCode,"病号不可为空");
+        Assert.hasText(tenantId,"医院id不可为空");
+        Assert.notNull(startTime,"手术开始时间不可为空");
+
+        List<BusInfusionHistoryEntity> infusionHistories = this.list(new QueryWrapper<BusInfusionHistoryEntity>()
+                .lambda()
+                .eq(BusInfusionHistoryEntity::getTenantId, tenantId)
+                .eq(BusInfusionHistoryEntity::getPatientCode, patientCode)
+                .lt(BusInfusionHistoryEntity::getStartTime, startTime)
+                .gt(BusInfusionHistoryEntity::getClinicStartTime, startTime));
+        if(CollectionUtil.isNotEmpty(infusionHistories)){
+            infusionHistories.sort(Comparator.comparing(BusInfusionHistoryEntity::getStartTime));
+            infusionHistories.forEach(infusion->infusion.setClinicId(clinicId));
+            clinicService.update(new UpdateWrapper<BusClinicEntity>().lambda().eq(BusClinicEntity::getId,clinicId)
+            .set(BusClinicEntity::getMonitorStartTime,infusionHistories.get(0).getStartTime()));
+        }
+
+    }
 }

+ 172 - 20
coffee-system/src/main/java/com/coffee/bus/service/LocalBusPatientService.java

@@ -1,35 +1,48 @@
 package com.coffee.bus.service;
 
 import cn.hutool.core.collection.CollectionUtil;
+import cn.hutool.core.date.DateUtil;
+import cn.hutool.core.date.LocalDateTimeUtil;
+import cn.hutool.json.JSONObject;
+import cn.hutool.json.JSONUtil;
 import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
 import cn.hutool.core.util.StrUtil;
-import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
-import com.baomidou.mybatisplus.core.conditions.update.UpdateWrapper;
 import com.baomidou.mybatisplus.core.metadata.IPage;
 import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
 import com.coffee.bus.entity.BusClinicEntity;
 import com.coffee.bus.entity.BusPatientEntity;
 import com.coffee.bus.entity.PatientDeviceRepeatDomain;
-import com.coffee.bus.entity.PatientMonitorDomain;
-import com.coffee.bus.mapper.BusClinicMapper;
+import com.coffee.bus.enums.DeviceAlarmEnum;
+import com.coffee.bus.enums.DeviceStatusEnum;
+import com.coffee.bus.enums.PatientAlarmEnum;
+import com.coffee.bus.his.HisScriptSession;
+import com.coffee.bus.his.HisScriptSessionManager;
+import com.coffee.bus.his.strategy.HisStrategyManager;
+import com.coffee.bus.service.dto.*;
 import com.coffee.bus.mapper.BusPatientMapper;
 import com.coffee.bus.registry.patient.PatientOperator;
 import com.coffee.bus.registry.patient.PatientRegistry;
 import com.coffee.bus.registry.patient.bean.PatientCacheInfo;
-import com.coffee.bus.service.dto.PatientDeviceNoneResult;
-import com.coffee.bus.service.dto.PatientDeviceRepeatResult;
-import com.coffee.bus.service.dto.PatientMonitorQuery;
+import com.coffee.bus.utils.WsPublishUtils;
+import com.coffee.common.config.websocket.WebSocketConstant;
 import com.coffee.common.crud.BaseService;
-import lombok.AllArgsConstructor;
+import com.coffee.common.enums.SexEnum;
+import com.coffee.common.result.R;
 import lombok.extern.slf4j.Slf4j;
+import net.bytebuddy.asm.Advice;
 import org.springframework.beans.factory.annotation.Autowired;
 import org.springframework.context.annotation.Lazy;
-import org.springframework.data.domain.PageRequest;
 import org.springframework.scheduling.annotation.Async;
 import org.springframework.stereotype.Service;
 import org.springframework.transaction.annotation.Transactional;
+import org.springframework.web.context.request.async.DeferredResult;
 
+import java.time.LocalDateTime;
 import java.util.*;
+import java.util.concurrent.CompletableFuture;
+import java.util.concurrent.Executors;
+import java.util.concurrent.ScheduledExecutorService;
+import java.util.concurrent.TimeUnit;
 
 /**
  * @author lifang
@@ -48,9 +61,24 @@ public class LocalBusPatientService extends BaseService<BusPatientMapper, BusPat
     @Lazy
     private PatientRegistry patientRegistry;
 
+    @Autowired
+    @Lazy
+    private HisScriptSessionManager scriptSessionManager;
+
+    @Autowired
+    @Lazy
+    private WsPublishUtils wsPublishUtils;
+
+    private ScheduledExecutorService executorService = Executors.newSingleThreadScheduledExecutor();
+
     @Override
     public void validateBeforeSave(BusPatientEntity entity) {
-
+        if(entity.getGender()==null){
+            entity.setGender(SexEnum.UNKNOW);
+        }
+        if(entity.getAlarm()==null){
+            entity.setAlarm(PatientAlarmEnum.NONE);
+        }
     }
 
     @Override
@@ -63,16 +91,26 @@ public class LocalBusPatientService extends BaseService<BusPatientMapper, BusPat
 
     }
 
-
+    @Override
+    public void postSave(BusPatientEntity entity) {
+        super.postSave(entity);
+        //新增病人后推送主题,延迟推送,保证处理逻辑已全部完成
+        executorService.schedule(()->{
+                    wsPublishUtils.publishPatientAdd(entity.getCode(),entity.getTenantId());
+                    wsPublishUtils.publishMonitorTotalCount(entity.getTenantId());
+                }
+                ,2, TimeUnit.SECONDS);
+    }
 
     /**
-     * 异步获取病人信息 todo
+     * 获取病人信息
      * @param hospitalId  医院id
      * @param patientCode 病号
+     * @param sync 是否为同步操作
      */
-    @Async
-    public void syncGetPatientInfoFromHis(String hospitalId,String patientCode){
-
+    public DeferredResult<R<BusClinicEntity>> getPatientInfoFromHis(String hospitalId, String patientCode, long timeout,boolean sync){
+        HisScriptSession hisScriptSession = scriptSessionManager.get(hospitalId);
+        return sync?hisScriptSession.syncGetPatientInfo(patientCode,timeout,TimeUnit.SECONDS):hisScriptSession.asyncGetPatientInfo(patientCode,timeout,TimeUnit.SECONDS,true);
     }
 
     /**
@@ -83,7 +121,7 @@ public class LocalBusPatientService extends BaseService<BusPatientMapper, BusPat
         List<PatientDeviceRepeatDomain> patientDeviceRepeats = this.baseMapper.selectRepeatDevice();
         Map<String, PatientDeviceRepeatResult> resultMap = new HashMap<>();
         patientDeviceRepeats.forEach(deviceRepeat->{
-            PatientDeviceRepeatResult repeatResult = resultMap.computeIfAbsent(deviceRepeat.getCode(),k->
+            PatientDeviceRepeatResult repeatResult = resultMap.computeIfAbsent(deviceRepeat.getCode()+deviceRepeat.getClinicId(),k->
                     PatientDeviceRepeatResult.of(
                             deviceRepeat.getName(),
                             deviceRepeat.getGender(),
@@ -92,6 +130,7 @@ public class LocalBusPatientService extends BaseService<BusPatientMapper, BusPat
                             deviceRepeat.getWard(),
                             deviceRepeat.getBedNo(),
                             deviceRepeat.getClinicName(),
+                            deviceRepeat.getClinicId(),
                             new ArrayList<>())
             );
             List<PatientDeviceRepeatResult.DeviceRunningSmallInfo> deviceRunningSmallInfos = Optional.ofNullable(repeatResult.getDevices()).orElse(new ArrayList<>());
@@ -117,11 +156,11 @@ public class LocalBusPatientService extends BaseService<BusPatientMapper, BusPat
         return this.baseMapper.selectNoneDevice();
     }
 
-    public List<PatientMonitorDomain> selectAll(PatientMonitorQuery query) {
-        Page<PatientMonitorDomain> page = new Page<>(0, 500, false);
-        IPage<PatientMonitorDomain> result = this.baseMapper.selectMonitor(page,query);
+    public List<PatientMonitorResult> selectAll(PatientMonitorQuery query) {
+        Page<PatientMonitorResult> page = new Page<>(0, 500, false);
+        IPage<PatientMonitorResult> result = this.baseMapper.selectMonitor(page,query);
         if(CollectionUtil.isNotEmpty(result.getRecords())){
-            result.getRecords().forEach(PatientMonitorDomain::handleWarn);
+            result.getRecords().forEach(PatientMonitorResult::handleWarn);
         }
         return result.getRecords();
     }
@@ -171,5 +210,118 @@ public class LocalBusPatientService extends BaseService<BusPatientMapper, BusPat
         patientOperator.setName(patient.getName());
         patientOperator.setBedNo(clinic.getBedNo());
         patientOperator.setWard(clinic.getWard());
+
+        CompletableFuture.runAsync(()->{
+            wsPublishUtils.publishPatientMonitor(patient.getCode(),patient.getTenantId());
+        });
+    }
+
+    /**
+     * 根据病号查询临床监控记录
+     * @author lifang
+     * @param patientCode 病号
+     * @param tenantId 医院id
+     * @return
+     */
+    public PatientMonitorResult lookMonitorByPatientCode(String patientCode,String tenantId) {
+        try {
+            return this.baseMapper.findByPatientCode(tenantId, patientCode);
+        } catch (Exception e) {
+            log.error("根据病号查询临床失败,",e.getMessage());
+            return null;
+        }
+    }
+
+    /**
+     * 描述: 设备状态数量统计
+     * @author lifang
+     * @date 2022/5/8 21:52
+     * @param tenantId 医院id 用户请求时传输null
+     * @return MonitorStatusStatsCountResult
+     */
+    public MonitorStatusStatsCountResult statusStats(String tenantId) {
+        PatientMonitorQuery query = new PatientMonitorQuery();
+        query.setTenantId(tenantId);
+        List<PatientMonitorResult> patientMonitorResults = this.selectAll(query);
+        MonitorStatusStatsCountResult result = new MonitorStatusStatsCountResult();
+        if(CollectionUtil.isNotEmpty(patientMonitorResults)){
+            patientMonitorResults.forEach(monitor->{
+                //运行数量
+                if(DeviceStatusEnum.Running.equals(monitor.getDeviceRunState())){
+                    result.setRunningCount(result.getRunningCount()+1);
+                }
+                //todo 待结束数量
+                //报警数量
+                if(monitor.getDeviceAlarm()!=null&&!monitor.getDeviceAlarm().equals(DeviceAlarmEnum.None)){
+                    result.setAlarmCount(result.getAlarmCount()+1);
+                }
+                //提醒数量
+                if(Boolean.TRUE.equals(monitor.getWarnAnalgesicPoor())
+                        ||Boolean.TRUE.equals(monitor.getWarnLowBattery())
+                        ||Boolean.TRUE.equals(monitor.getWarnWillFinished())
+                        ||monitor.getWarnFlow()!=null){
+                    result.setWarnCount(result.getWarnCount()+1);
+                }
+            });
+        }
+        return result;
+    }
+
+    /**
+     * 描述: 按照时间对输注监控进行统计
+     * @author lifang
+     * @date 2022/5/8 22:40
+     * @param tenantId 医院id
+     * @return MonitorTimeStatsCountResult
+     */
+    public MonitorTimeStatsCountResult timeStats(String tenantId) {
+        PatientMonitorQuery query = new PatientMonitorQuery();
+        query.setTenantId(tenantId);
+        List<PatientMonitorResult> patientMonitorResults = this.selectAll(query);
+        MonitorTimeStatsCountResult result = new MonitorTimeStatsCountResult();
+        patientMonitorResults.forEach(monitor->{
+            Date startTime = monitor.getMonitorStartTime();
+            if(startTime==null){
+                return;
+            }
+            if (includeTimes(startTime, 0)) {
+                result.setToday(result.getToday()+1);
+                return;
+            }
+            if (includeTimes(startTime, 1)) {
+                result.setOneDay(result.getOneDay()+1);
+                return;
+            }
+            if (includeTimes(startTime, 2)) {
+                result.setTwoDay(result.getTwoDay()+1);
+                return;
+            }
+            if (includeTimes(startTime, 3)) {
+                result.setThreeDay(result.getThreeDay()+1);
+                return;
+            }
+            result.setBeyondThreeDay(result.getBeyondThreeDay()+1);
+        });
+
+        return result;
+    }
+
+    /**
+     * 描述: 判断所给时间是否在存在于某一时间段内
+     * @author lifang
+     * @date 2022/5/8 22:47
+     * @param time 时间
+     * @param offset 时间偏移量,单位:天 以当天时间为基准进行偏移
+     * @return boolean
+     */
+    private boolean includeTimes(Date time,int offset){
+        if(time==null){
+            return false;
+        }
+        LocalDateTime dateTime = LocalDateTime.now().plusDays(offset);
+        LocalDateTime beginTime = LocalDateTimeUtil.beginOfDay(dateTime);
+        LocalDateTime endTime = LocalDateTimeUtil.endOfDay(dateTime);
+        return beginTime.getSecond()<time.getSeconds()
+                && time.getSeconds()<endTime.getSecond();
     }
 }

Alguns ficheiros não foram mostrados porque muitos ficheiros mudaram neste diff