Просмотр исходного кода

add 增加线程异常处理
fix 修复已知bug

A17404李放 3 лет назад
Родитель
Сommit
88b173d724
31 измененных файлов с 680 добавлено и 667 удалено
  1. 5 0
      coffee-admin/src/test/java/com/coffee/admin/BusClinicTest.java
  2. 1 1
      coffee-admin/src/test/java/com/coffee/admin/BusDeviceAlarmTest.java
  3. 23 0
      coffee-common/src/main/java/com/coffee/common/thread/DefaultHandlerThreadFactory.java
  4. 18 0
      coffee-common/src/main/java/com/coffee/common/thread/DefaultUncaughtExceptionHandler.java
  5. 48 0
      coffee-common/src/main/java/com/coffee/common/thread/ExecutorConfig.java
  6. 0 1
      coffee-framework/src/main/java/com/coffee/framework/config/WebAppMvcConfig.java
  7. 0 94
      coffee-system/src/main/java/com/coffee/bus/bean/HisInfo.java
  8. 4 1
      coffee-system/src/main/java/com/coffee/bus/controller/BusClinicController.java
  9. 4 5
      coffee-system/src/main/java/com/coffee/bus/controller/BusDeviceHistoryController.java
  10. 3 1
      coffee-system/src/main/java/com/coffee/bus/controller/BusPatientController.java
  11. 0 24
      coffee-system/src/main/java/com/coffee/bus/entity/BusClinicEntity.java
  12. 0 43
      coffee-system/src/main/java/com/coffee/bus/entity/BusDeviceHistoryEntity.java
  13. 5 3
      coffee-system/src/main/java/com/coffee/bus/entity/BusHospitalLogEntity.java
  14. 0 1
      coffee-system/src/main/java/com/coffee/bus/entity/BusInfusionHistoryEntity.java
  15. 0 11
      coffee-system/src/main/java/com/coffee/bus/entity/BusPatientEntity.java
  16. 1 1
      coffee-system/src/main/java/com/coffee/bus/hospital/HospitalManager.java
  17. 38 28
      coffee-system/src/main/java/com/coffee/bus/hospital/his/HisScriptSession.java
  18. 5 2
      coffee-system/src/main/java/com/coffee/bus/hospital/his/HisScriptSessionManager.java
  19. 1 1
      coffee-system/src/main/java/com/coffee/bus/hospital/his/strategy/all/MoreToLessHisStrategyHandler.java
  20. 0 10
      coffee-system/src/main/java/com/coffee/bus/registry/device/ClusterDeviceOperator.java
  21. 6 2
      coffee-system/src/main/java/com/coffee/bus/registry/device/ClusterDeviceRegistry.java
  22. 0 13
      coffee-system/src/main/java/com/coffee/bus/registry/device/DeviceOperator.java
  23. 1 1
      coffee-system/src/main/java/com/coffee/bus/service/LocalBusClinicService.java
  24. 106 49
      coffee-system/src/main/java/com/coffee/bus/service/LocalBusInfusionHistoryService.java
  25. 1 7
      coffee-system/src/main/java/com/coffee/bus/service/LocalBusPatientService.java
  26. 1 0
      coffee-system/src/main/java/com/coffee/bus/service/dto/ClinicAnalClinicRecord.java
  27. 10 6
      coffee-system/src/main/java/com/coffee/bus/service/dto/ManualUndoConfig.java
  28. 0 1
      coffee-system/src/main/java/com/coffee/bus/utils/WsPublishUtils.java
  29. 44 15
      coffee-system/src/main/java/com/coffee/bus/websocket/listener/DeviceInfoListener.java
  30. 3 3
      coffee-system/src/main/java/com/coffee/bus/websocket/listener/HisInfoListener.java
  31. 352 343
      coffee-system/src/main/resources/mapper/bus/BusPatientMapper.xml

+ 5 - 0
coffee-admin/src/test/java/com/coffee/admin/BusClinicTest.java

@@ -99,4 +99,9 @@ private LocalBusDocService docService;
         int i=1/0;
     }
 
+
+    public void publish(){
+
+    }
+
 }

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

@@ -55,6 +55,6 @@ public class BusDeviceAlarmTest {
         DeviceAlarmQuery query = new DeviceAlarmQuery();
         query.setHositalName("驼人医疗器械有限公司");
         query.setTenantId("1");
-        System.out.println(controller.deviceUse(query));
+//        System.out.println(controller.deviceUse(query));
     }
 }

+ 23 - 0
coffee-common/src/main/java/com/coffee/common/thread/DefaultHandlerThreadFactory.java

@@ -0,0 +1,23 @@
+package com.coffee.common.thread;
+
+import org.jetbrains.annotations.NotNull;
+
+import java.util.concurrent.ThreadFactory;
+
+/**
+ * @author lifang
+ * @version 1.0.0
+ * @ClassName DefaultHandlerThreadFactory.java
+ * @Description 默认线程工厂
+ * @createTime 2022年05月31日 17:31:00
+ */
+public class DefaultHandlerThreadFactory implements ThreadFactory {
+    @Override
+    public Thread newThread(@NotNull Runnable r) {
+        Thread t = new Thread(r);
+        t.setName("default-");
+        //设定线程工厂的异常处理器
+        t.setUncaughtExceptionHandler(new DefaultUncaughtExceptionHandler());
+        return t;
+    }
+}

+ 18 - 0
coffee-common/src/main/java/com/coffee/common/thread/DefaultUncaughtExceptionHandler.java

@@ -0,0 +1,18 @@
+package com.coffee.common.thread;
+
+import lombok.extern.slf4j.Slf4j;
+
+/**
+ * @author lifang
+ * @version 1.0.0
+ * @ClassName DefaultUncaughtExceptionHandler.java
+ * @Description 定义多线程异常处理器
+ * @createTime 2022年05月31日 17:30:00
+ */
+@Slf4j
+public class DefaultUncaughtExceptionHandler implements Thread.UncaughtExceptionHandler {
+    @Override
+    public void uncaughtException(Thread t, Throwable e) {
+        log.error("线程:{}运行失败,error,",t.getName(),e);
+    }
+}

+ 48 - 0
coffee-common/src/main/java/com/coffee/common/thread/ExecutorConfig.java

@@ -0,0 +1,48 @@
+package com.coffee.common.thread;
+
+import org.springframework.boot.autoconfigure.task.TaskSchedulingProperties;
+import org.springframework.context.annotation.Bean;
+import org.springframework.context.annotation.Configuration;
+import org.springframework.context.annotation.Primary;
+import org.springframework.scheduling.annotation.EnableAsync;
+import org.springframework.scheduling.concurrent.ThreadPoolTaskExecutor;
+
+import java.util.concurrent.Executor;
+import java.util.concurrent.ThreadPoolExecutor;
+
+@Configuration
+@EnableAsync
+public class ExecutorConfig {
+
+    @Bean
+    @Primary
+    public Executor defaultExecutor(TaskSchedulingProperties properties) {
+        TaskSchedulingProperties.Shutdown shutdown = properties.getShutdown();
+        //获取当前机器的核数
+        ThreadPoolTaskExecutor executor = new ThreadPoolTaskExecutor();
+        //配置核心线程数
+        executor.setCorePoolSize(properties.getPool().getSize());
+        //配置最大线程数
+        executor.setMaxPoolSize(properties.getPool().getSize());
+        if(shutdown!=null){
+            executor.setWaitForTasksToCompleteOnShutdown(shutdown.isAwaitTermination());
+            if(shutdown.isAwaitTermination()){
+                executor.setAwaitTerminationMillis(shutdown.getAwaitTerminationPeriod().toMillis());
+            }
+        }
+
+        //配置队列大小
+        executor.setQueueCapacity(1000);
+        //线程存活时间
+        executor.setKeepAliveSeconds(60);
+        //线程工厂
+        executor.setThreadFactory(new DefaultHandlerThreadFactory());
+        //配置线程池中的线程的名称前缀
+        executor.setThreadNamePrefix(properties.getThreadNamePrefix());
+        // CALLER_RUNS:不在新线程中执行任务,而是有调用者所在的线程来执行
+        executor.setRejectedExecutionHandler(new ThreadPoolExecutor.CallerRunsPolicy());
+        //执行初始化
+        executor.initialize();
+        return executor;
+    }
+}

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

@@ -11,7 +11,6 @@ import com.fasterxml.jackson.databind.*;
 import com.fasterxml.jackson.databind.deser.std.StdScalarDeserializer;
 import com.fasterxml.jackson.databind.module.SimpleModule;
 import com.fasterxml.jackson.databind.ser.std.StringSerializer;
-import com.sun.org.apache.xpath.internal.operations.Bool;
 import org.springframework.beans.factory.annotation.Autowired;
 import org.springframework.boot.autoconfigure.EnableAutoConfiguration;
 import org.springframework.context.annotation.Configuration;

+ 0 - 94
coffee-system/src/main/java/com/coffee/bus/bean/HisInfo.java

@@ -1,94 +0,0 @@
-package com.coffee.bus.bean;
-
-import com.coffee.common.enums.SexEnum;
-import lombok.Data;
-
-import java.util.Date;
-
-/**
- * @author lifang
- * @version 1.0.0
- * @ClassName HisInfo.java
- * @Description his系统接收信息
- * @createTime 2022年03月29日 16:39:00
- */
-@Data
-public class HisInfo {
-    /**
-     * 医院id
-     */
-    private String hospitalId;
-    /**
-     * 住院号
-     */
-    private String patientCode;
-    /**
-     * 姓名
-     */
-    private String patientName;
-    /**
-     * 性别
-     */
-    private SexEnum gender;
-    /**
-     * 生日
-     */
-    private String birthday;
-    /**
-     * 年龄
-     */
-    private String age;
-    /**
-     * 身高
-     */
-    private String height;
-    /**
-     * 体重
-     */
-    private String weight;
-    /**
-     * 病区
-     */
-    private String ward;
-    /**
-     * 床号
-     */
-    private String bedNo;
-    /**
-     * 手术名称
-     */
-    private String operation;
-    /**
-     * 手术医生
-     */
-    private String surgeon;
-    /**
-     * 手术开始时间
-     */
-    private Date operationTime;
-    /**
-     * asa分级
-     */
-    private String asa;
-    /**
-     * PCA镇痛模式
-     */
-    private String easeMode;
-    /**
-     * 配方
-     */
-    private String formula;
-    /**
-     * 麻醉医生
-     */
-    private String doctor;
-    /**
-     * 配置医生(配置人员、配药医生)
-     */
-    private String configPerson;
-    /**
-     * 医嘱
-     */
-    private String entrust;
-
-}

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

@@ -128,9 +128,12 @@ public class BusClinicController {
     public R<Boolean> edit(@RequestAttribute("tenantId")@ApiParam(hidden = true) String tenantId, @RequestBody @Validated ClinicEditVo entity){
         if(entity.getHaveDevice()){
             BusClinicEntity clinic = entity.getClinic();
-            if(clinic==null|| StrUtil.isEmpty(clinic.getId())){
+            if(clinic==null){
                 throw new CustomException("临床信息不能为空");
             }
+            BusPatientEntity patient = patientService.getOne(new QueryWrapper<BusPatientEntity>().lambda().eq(BusPatientEntity::getCode,clinic.getPatientCode()));
+            //仅更新最新的临床数据
+            clinic.setId(patient.getClinicId());
             clinic.setTenantId(tenantId);
             patientService.manualEdit(clinic);
             return R.success(true);

+ 4 - 5
coffee-system/src/main/java/com/coffee/bus/controller/BusDeviceHistoryController.java

@@ -16,12 +16,10 @@ import com.coffee.common.crud.controller.BaseCrudController;
 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.validation.annotation.Validated;
-import org.springframework.web.bind.annotation.PostMapping;
-import org.springframework.web.bind.annotation.RequestBody;
-import org.springframework.web.bind.annotation.RequestMapping;
-import org.springframework.web.bind.annotation.RestController;
+import org.springframework.web.bind.annotation.*;
 
 import java.util.List;
 
@@ -59,7 +57,8 @@ public class BusDeviceHistoryController extends BaseCrudController<BusDeviceHist
     @PostMapping("/deviceUse")
     @SaCheckPermission("bus:device:use")
     @ApiOperation(value = "设备使用查询",notes = "权限:【bus:device:use】")
-    public R<List<DeviceUse>> deviceUse(@RequestBody @Validated DeviceAlarmQuery query){
+    public R<List<DeviceUse>> deviceUse(@RequestAttribute(value = "tenantId",required = false)@ApiParam(hidden = true) String tenantId, @RequestBody @Validated DeviceAlarmQuery query){
+        query.setTenantId(tenantId);
         return R.success(deviceAlarmService.selectCountAlarm(query));
     }
 

+ 3 - 1
coffee-system/src/main/java/com/coffee/bus/controller/BusPatientController.java

@@ -110,6 +110,7 @@ public class BusPatientController  implements BaseQueryController<BusPatientEnti
         if(haveDevice){
             R<Boolean> result = monitorFinished(monitorFinishedVo, tenantId);
             wsPublishUtils.publishMonitorTotalCount(tenantId);
+            wsPublishUtils.publishDeviceNone(tenantId);
             return result;
         }else {
             return manualFinished(monitorFinishedVo);
@@ -207,7 +208,8 @@ public class BusPatientController  implements BaseQueryController<BusPatientEnti
         infusionService.undo(undoConfig,false);
         PatientOperator operator = patientRegistry.getOperator(undoConfig.getTenantId(), undoConfig.getPatientCode());
         //判断当前病号下是否还存在副泵
-        long count = infusionService.count(new QueryWrapper<BusInfusionHistoryEntity>().lambda().eq(BusInfusionHistoryEntity::getClinicId, operator.getClinicId())
+        long count = infusionService.count(new QueryWrapper<BusInfusionHistoryEntity>().lambda()
+                .eq(BusInfusionHistoryEntity::getClinicId, operator.getClinicId())
                 .eq(BusInfusionHistoryEntity::getFinished,false)
                 .eq(BusInfusionHistoryEntity::getIsUndo,false));
         //处理缓存信息

+ 0 - 24
coffee-system/src/main/java/com/coffee/bus/entity/BusClinicEntity.java

@@ -5,7 +5,6 @@ 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.coffee.bus.bean.HisInfo;
 import com.coffee.bus.service.dto.FormulaDrugDomain;
 import com.coffee.bus.service.dto.UndoDeviceConfig;
 import com.coffee.common.entity.TenantGenericEntity;
@@ -119,27 +118,4 @@ public class BusClinicEntity extends TenantGenericEntity<String,String> {
 
     @ApiModelProperty(value = "医嘱")
     private String entrust;
-
-    public static BusClinicEntity of(HisInfo hisInfo){
-        BusClinicEntity clinic = new BusClinicEntity();
-        clinic.setTenantId(hisInfo.getHospitalId());
-        clinic.setPatientCode(hisInfo.getPatientCode());
-        clinic.setPatientName(hisInfo.getPatientName());
-        clinic.setPatientGender(hisInfo.getGender());
-        clinic.setPatientAge(Integer.valueOf(hisInfo.getAge()));
-        clinic.setWeight(hisInfo.getWeight());
-        clinic.setHeight(hisInfo.getHeight());
-        //病区 需新增 todo
-        clinic.setWard(hisInfo.getWard());
-        clinic.setBedNo(hisInfo.getBedNo());
-        clinic.setSurgeryName(hisInfo.getOperation());
-        clinic.setSurgeryDoctor(hisInfo.getSurgeon());
-        clinic.setStartTime(hisInfo.getOperationTime());
-        //asa分级 todo
-        //easymode todo
-//        clinic.setFormula(hisInfo.getFormula());
-        clinic.setConfigPerson(hisInfo.getConfigPerson());
-        clinic.setEntrust(hisInfo.getEntrust());
-        return clinic;
-    }
 }

+ 0 - 43
coffee-system/src/main/java/com/coffee/bus/entity/BusDeviceHistoryEntity.java

@@ -57,52 +57,9 @@ public class BusDeviceHistoryEntity extends CommonDeviceParam<String,String> {
     public static BusDeviceHistoryEntity parseRunningInfo(BusDeviceRunningEntity running){
         BusDeviceHistoryEntity entity = new BusDeviceHistoryEntity();
         BeanUtil.copyProperties(running,entity);
-//        entity.setDeviceId(running.getDeviceId());
-//        entity.setType(running.getType());
-//        entity.setClassification(running.getClassification());
-//        entity.setTenantId(running.getTenantId());
         entity.setInfusionId(running.getInfusionId());
         entity.setInfusionModifyId(running.getInfusionModifyId());
-
-//        entity.setTotalDose(running.getTotalDose());
-//        entity.setFirstDose(running.getFirstDose());
-//        entity.setRemainDose(running.getRemainDose());
-//        entity.setInputDose(running.getInputDose());
-//        entity.setContinueDose(running.getContinueDose());
-//        entity.setAppendDose(running.getAppendDose());
-//        entity.setMaxDose(running.getMaxDose());
-//        entity.setSelfControlLockTime(running.getSelfControlLockTime());
-//        entity.setSelfControlCount(running.getSelfControlCount());
-//        entity.setPcaValidCount(running.getPcaValidCount());
-//        entity.setPcaInvalidCount(running.getPcaInvalidCount());
-//        entity.setPcaTotalCount(running.getPcaTotalCount());
-//        entity.setDataNumber(running.getDataNumber());
-//        /**
-//         * 脉冲泵参数
-//         */
-//        entity.setPulseDose(running.getPulseDose());
-//        entity.setPulseFirstLockTime(running.getPulseFirstLockTime());
-//        entity.setPulseLockTime(running.getPulseLockTime());
-//        /**
-//         * 智能泵参数
-//         */
-//        entity.setFlowAdjustRate(running.getFlowAdjustRate());
-//        entity.setFlowCount(running.getFlowCount());
-//        entity.setFlowDownCycle(running.getFlowDownCycle());
-//        entity.setFlowUpCycle(running.getFlowUpCycle());
-//        entity.setFlowDownLimit(running.getFlowDownLimit());
-//        entity.setFlowUpLimit(running.getFlowUpLimit());
-//
         entity.setUploadTime(running.getUploadTime());
-//        entity.setRunState(running.getRunState());
-//        entity.setWarnAnalgesicPoor(running.getWarnAnalgesicPoor());
-//        entity.setWarnLowBattery(running.getWarnAnalgesicPoor());
-//        entity.setWarnWillFinished(running.getWarnAnalgesicPoor());
-//        entity.setAlarm(running.getAlarm());
-//
-//        entity.setWard(running.getWard());
-//        entity.setBedNo(running.getBedNo());
-//        entity.setDataNumber(running.getDataNumber());
         entity.setMaster(running.getMaster());
         entity.setTenantId(running.getTenantId());
         return entity;

+ 5 - 3
coffee-system/src/main/java/com/coffee/bus/entity/BusHospitalLogEntity.java

@@ -35,12 +35,13 @@ public class BusHospitalLogEntity extends TenantGenericEntity<String,String> {
     @ApiModelProperty("脚本是否执行成功")
     private boolean success;
 
+    private String patientCode;
+
     @ApiModelProperty("输入参数")
     private String input;
 
     @ApiModelProperty(value = "医院数据处理结果")
-    @TableField(typeHandler = FastjsonTypeHandler.class)
-    private JSON result;
+    private Object result;
 
     @ApiModelProperty("错误消息")
     private String message;
@@ -48,7 +49,7 @@ public class BusHospitalLogEntity extends TenantGenericEntity<String,String> {
     @ApiModelProperty("本消息处理运行时间")
     private long useTime;
 
-    public static BusHospitalLogEntity of(ExecuteResult source,String tenantId){
+    public static BusHospitalLogEntity of(ExecuteResult source,String tenantId,String patientCode){
         BusHospitalLogEntity result = new BusHospitalLogEntity();
         result.setTenantId(tenantId);
         result.setInput(source.getInput());
@@ -56,6 +57,7 @@ public class BusHospitalLogEntity extends TenantGenericEntity<String,String> {
         result.setResult(source.getResult());
         result.setSuccess(source.isSuccess());
         result.setUseTime(source.getUseTime());
+        result.setPatientCode(patientCode);
         return result;
     }
 }

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

@@ -122,5 +122,4 @@ public class BusInfusionHistoryEntity extends CommonDeviceParam<String,String> {
         this.setAlarm(DeviceAlarmUtils.getAlarm(items.getInteger(PumpParams.alarmStatus)));
         // 预报
     }
-
 }

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

@@ -2,7 +2,6 @@ package com.coffee.bus.entity;
 
 import com.baomidou.mybatisplus.annotation.TableField;
 import com.baomidou.mybatisplus.annotation.TableName;
-import com.coffee.bus.bean.HisInfo;
 import com.coffee.bus.enums.PatientAlarmEnum;
 import com.coffee.common.entity.TenantGenericEntity;
 import com.coffee.common.enums.SexEnum;
@@ -13,8 +12,6 @@ import lombok.EqualsAndHashCode;
 import lombok.ToString;
 import org.hibernate.validator.constraints.Length;
 
-import java.util.Date;
-
 /**
  * @author lifang
  * @version 1.0.0
@@ -51,14 +48,6 @@ public class BusPatientEntity extends TenantGenericEntity<String,String> {
     @ApiModelProperty(value = "病人报警信息",example = "泵重复,无泵")
     private PatientAlarmEnum alarm;
 
-    public static BusPatientEntity of(HisInfo hisInfo){
-        BusPatientEntity patient = new BusPatientEntity();
-        patient.setCode(hisInfo.getPatientCode());
-        patient.setGender(hisInfo.getGender());
-        patient.setName(hisInfo.getPatientName());
-        patient.setTenantId(hisInfo.getHospitalId());
-        return patient;
-    }
 
     public static BusPatientEntity of(BusClinicEntity clinic){
         BusPatientEntity patient = new BusPatientEntity();

+ 1 - 1
coffee-system/src/main/java/com/coffee/bus/hospital/HospitalManager.java

@@ -95,7 +95,7 @@ public class HospitalManager {
     }
 
     private void init(ConfigStorageManager configStorageManager){
-        this.scriptSession=new HisScriptSession(hospitalId,scriptManager,configStorageManager,clinicService,hospitalService,hospitalLogService);
+        this.scriptSession=new HisScriptSession(hospitalId,scriptManager,configStorageManager,clinicService,hospitalService,hospitalLogService,patientService);
         refreshInfo();
         refreshConfig();
         refreshScript();

+ 38 - 28
coffee-system/src/main/java/com/coffee/bus/hospital/his/HisScriptSession.java

@@ -1,38 +1,37 @@
 package com.coffee.bus.hospital.his;
 
-import cn.hutool.core.bean.BeanUtil;
 import cn.hutool.core.collection.CollectionUtil;
-import cn.hutool.core.date.DateField;
-import cn.hutool.core.date.DateUtil;
-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.query.QueryWrapper;
 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.entity.BusHospitalLogEntity;
+import com.coffee.bus.entity.BusPatientEntity;
 import com.coffee.bus.listener.event.bean.HisEvent;
 import com.coffee.bus.hospital.script.DefaultParse;
 import com.coffee.bus.service.LocalBusHospitalLogService;
+import com.coffee.bus.service.LocalBusPatientService;
 import com.coffee.common.exception.ExecuteResult;
 import com.coffee.bus.hospital.script.ScriptManager;
 import com.coffee.bus.hospital.script.ScriptParse;
 import com.coffee.bus.service.LocalBusClinicService;
 import com.coffee.bus.service.LocalBusHospitalService;
-import com.coffee.bus.service.dto.FormulaDrugDetailDomain;
-import com.coffee.bus.service.dto.FormulaDrugDomain;
 import com.coffee.common.cache.ConfigStorage;
 import com.coffee.common.cache.manager.ConfigStorageManager;
 import com.coffee.common.cache.value.Value;
-import com.coffee.common.enums.SexEnum;
 import com.coffee.common.exception.CustomException;
 import com.coffee.common.result.R;
+import com.coffee.common.thread.DefaultHandlerThreadFactory;
+import com.coffee.common.thread.DefaultUncaughtExceptionHandler;
 import lombok.Getter;
 import lombok.extern.slf4j.Slf4j;
+import org.springframework.scheduling.concurrent.ThreadPoolTaskExecutor;
 import org.springframework.util.Assert;
 import org.springframework.web.context.request.async.DeferredResult;
 import org.tio.core.ChannelContext;
@@ -41,10 +40,7 @@ import org.tio.core.utils.TioUtils;
 import org.tio.websocket.common.WsResponse;
 
 import java.util.*;
-import java.util.concurrent.ConcurrentHashMap;
-import java.util.concurrent.Executors;
-import java.util.concurrent.ScheduledExecutorService;
-import java.util.concurrent.TimeUnit;
+import java.util.concurrent.*;
 
 /**
  * @author lifang
@@ -62,15 +58,17 @@ public class HisScriptSession {
     private LocalBusClinicService clinicService;
     private ConfigStorage clusterConfigStorage;
     private LocalBusHospitalService hospitalService;
+    private LocalBusPatientService patientService;
     private LocalBusHospitalLogService hospitalLogService;
     private Map<String,HisRequest> hisRequestMap=new ConcurrentHashMap<>();
 
-    public HisScriptSession(String hospitalId, ScriptManager scriptManager, ConfigStorageManager configStorageManager, LocalBusClinicService clinicService, LocalBusHospitalService hospitalService, LocalBusHospitalLogService hospitalLogService) {
+    public HisScriptSession(String hospitalId, ScriptManager scriptManager, ConfigStorageManager configStorageManager, LocalBusClinicService clinicService, LocalBusHospitalService hospitalService, LocalBusHospitalLogService hospitalLogService,LocalBusPatientService patientService) {
         this.hospitalId = hospitalId;
         this.scriptManager = scriptManager;
         this.clinicService = clinicService;
         this.hospitalService=hospitalService;
         this.hospitalLogService=hospitalLogService;
+        this.patientService=patientService;
         init(configStorageManager,hospitalId);
     }
 
@@ -110,6 +108,7 @@ public class HisScriptSession {
      */
     public  DeferredResult<R<BusClinicEntity>>  syncGetPatientInfo(String patientCode, long timeout, TimeUnit unit){
         if (!isOnline()) {
+            log.warn("医院不在线,拉取【{}】信息失败,拉取方式【同步】",patientCode);
             throw new CustomException("医院不在线,拉取信息失败");
         }
         String messageId = IdWorker.getIdStr();
@@ -151,7 +150,8 @@ public class HisScriptSession {
      */
     public  DeferredResult<R<BusClinicEntity>>  asyncGetPatientInfo(String patientCode,long timeout, TimeUnit unit,boolean needResult){
         if(!isOnline()){
-            //将请求缓存 todo
+            //将请求缓存
+            log.warn("医院不在线,拉取【{}】信息失败,是否为用户拉取【{}】,拉取方式【异步】",patientCode,needResult);
             throw new CustomException("医院不在线,拉取信息失败");
         }
         String messageId = IdWorker.getIdStr();
@@ -207,13 +207,12 @@ public class HisScriptSession {
             log.error("数据解析后转化为json失败,{},",text,e.getMessage());
             return null;
         }finally {
-            BusHospitalLogEntity hospitalLog = BusHospitalLogEntity.of(exec, this.getHospitalId());
+            BusHospitalLogEntity hospitalLog = BusHospitalLogEntity.of(exec, this.getHospitalId(),patientCode);
             try {
                 hospitalLogService.save(hospitalLog);
             }catch (Exception e){
                 log.error("医院日志存储异常,数据:【{}】",JSONUtil.toJsonStr(hospitalLog),e);
             }
-
         }
         //数据解析完成后发布
         JSONArray jsonArray = JSONUtil.parseArray(result);
@@ -221,10 +220,30 @@ public class HisScriptSession {
         if(CollectionUtil.isEmpty(sources)){
             return null;
         }else {
-            sources.forEach(source->source.setTenantId(hospitalId));
-            sources.sort(Comparator.comparing(BusClinicEntity::getStartTime));
-            SpringUtil.publishEvent(new HisEvent(this,sources,hospitalId,patientCode));
-            return sources.get(sources.size()-1);
+            List<BusClinicEntity> publish=new ArrayList<>();
+            //对数据去重, name+startTime进行唯一值判定
+            Map<String, BusClinicEntity> distinct = new HashMap<>();
+            sources.forEach(source->{
+                String key=source.getSurgeryName()+source.getStartTime();
+                distinct.computeIfAbsent(key,k->{
+                    publish.add(source);
+                    return source;
+                });
+            });
+            BusPatientEntity patient = patientService
+                    .getOne(new QueryWrapper<BusPatientEntity>().lambda().eq(BusPatientEntity::getCode, patientCode).eq(BusPatientEntity::getTenantId, hospitalId));
+            publish.sort(Comparator.comparing(BusClinicEntity::getStartTime));
+            publish.forEach(source->{
+                source.setTenantId(hospitalId);
+                //存在病号为输注监控、不存在病号为无泵监控
+                source.setMonitorType(patient!=null);
+            });
+
+            if(patient!=null){
+                //病号不存在,即认定为无泵输注信息
+                SpringUtil.publishEvent(new HisEvent(this,publish,hospitalId,patientCode));
+            }
+            return publish.get(publish.size()-1);
         }
     }
 
@@ -255,15 +274,6 @@ public class HisScriptSession {
         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);

+ 5 - 2
coffee-system/src/main/java/com/coffee/bus/hospital/his/HisScriptSessionManager.java

@@ -4,6 +4,7 @@ import com.coffee.bus.hospital.script.ScriptManager;
 import com.coffee.bus.service.LocalBusClinicService;
 import com.coffee.bus.service.LocalBusHospitalLogService;
 import com.coffee.bus.service.LocalBusHospitalService;
+import com.coffee.bus.service.LocalBusPatientService;
 import com.coffee.common.cache.manager.ClusterConfigStorageManager;
 import org.redisson.api.RedissonClient;
 import org.springframework.beans.factory.annotation.Autowired;
@@ -27,13 +28,15 @@ public class HisScriptSessionManager {
     private LocalBusHospitalService hospitalService;
     private ClusterConfigStorageManager configStorageManager;
     private LocalBusHospitalLogService hospitalLogService;
+    private LocalBusPatientService patientService;
     @Autowired
-    public HisScriptSessionManager( LocalBusClinicService clinicService, ScriptManager scriptManager, LocalBusHospitalService hospitalService, LocalBusHospitalLogService hospitalLogService, ClusterConfigStorageManager configStorageManager) {
+    public HisScriptSessionManager( LocalBusClinicService clinicService, ScriptManager scriptManager, LocalBusHospitalService hospitalService, LocalBusHospitalLogService hospitalLogService, ClusterConfigStorageManager configStorageManager,LocalBusPatientService patientService) {
         this.clinicService = clinicService;
         this.scriptManager = scriptManager;
         this.hospitalService = hospitalService;
         this.hospitalLogService=hospitalLogService;
         this.configStorageManager = configStorageManager;
+        this.patientService=patientService;
     }
 
     /**
@@ -55,7 +58,7 @@ public class HisScriptSessionManager {
      * @return HisScriptSession
      */
     public HisScriptSession register(String hospitalId){
-        return new HisScriptSession(hospitalId, scriptManager,configStorageManager, clinicService,hospitalService,hospitalLogService);
+        return new HisScriptSession(hospitalId, scriptManager,configStorageManager, clinicService,hospitalService,hospitalLogService,patientService);
     }
 
     /**

+ 1 - 1
coffee-system/src/main/java/com/coffee/bus/hospital/his/strategy/all/MoreToLessHisStrategyHandler.java

@@ -50,11 +50,11 @@ public class MoreToLessHisStrategyHandler implements HisAllStrategyHandler {
         //按照开始时间从大到小排序
         source.sort((t1,t2)->t2.getStartTime().compareTo(t1.getStartTime()));
         List<BusClinicEntity> insert=new LinkedList<>();
-        int subSize = CollectionUtil.size(source) - CollectionUtil.size(target);
         if (CollectionUtil.isEmpty(target)) {
             //所有的source都为新增
             insert.addAll(source);
         }else {
+            int subSize = CollectionUtil.size(source) - CollectionUtil.size(target);
             target.sort((t1,t2)->t2.getStartTime().compareTo(t1.getStartTime()));
             List<BusClinicEntity> compareSub = source.subList(subSize,CollectionUtil.size(source));
             if(timeRefresh(compareSub,target)){

+ 0 - 10
coffee-system/src/main/java/com/coffee/bus/registry/device/ClusterDeviceOperator.java

@@ -171,16 +171,6 @@ public class ClusterDeviceOperator implements DeviceOperator {
         return  getValue(DeviceKeyConstant.CLASSIFY).asString();
     }
 
-    @Override
-    public Boolean getUndo() {
-        return getValue(DeviceKeyConstant.UNDO).asBoolean();
-    }
-
-    @Override
-    public void setUndo(Boolean undo) {
-        configStorage.setConfig(DeviceKeyConstant.UNDO,undo);
-    }
-
     @Override
     public Date getUploadTime() {
         return getValue(DeviceKeyConstant.UPLOAD_TIME).asDate();

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

@@ -10,6 +10,9 @@ import com.coffee.common.cache.manager.ClusterConfigStorageManager;
 import lombok.AllArgsConstructor;
 import org.springframework.stereotype.Service;
 
+import java.util.Map;
+import java.util.concurrent.ConcurrentHashMap;
+
 /**
  * @author lifang
  * @version 1.0.0
@@ -24,13 +27,15 @@ public class ClusterDeviceRegistry implements DeviceRegistry {
     private final LocalBusDeviceService deviceService;
     private final ClusterConfigStorageManager configStorageManager;
     private final LocalBusInfusionModifyService infusionModifyService;
+
+    private static Map<String,ClusterDeviceOperator> operatorMap=new ConcurrentHashMap<>();
     @Override
     public DeviceOperator getOperator(String deviceId) {
         if(StrUtil.isEmpty(deviceId)){
             return null;
         }
         String key=getId()+deviceId;
-        ClusterDeviceOperator deviceOperator = new ClusterDeviceOperator( configStorageManager.getStorage(key));
+        ClusterDeviceOperator deviceOperator = operatorMap.computeIfAbsent(key,k->new ClusterDeviceOperator( configStorageManager.getStorage(k)));
         if(StrUtil.isNullOrUndefined(deviceOperator.getDeviceId())){
             //从数据库中获取数据
             BusInfusionHistoryEntity lastInfusion=infusionHistoryService.lastInfusion(deviceId);
@@ -48,7 +53,6 @@ public class ClusterDeviceRegistry implements DeviceRegistry {
             //设备运行信息
             if(lastInfusion!=null){
                 deviceOperator.setClassification(lastInfusion.getClassification());
-                deviceOperator.setUndo(lastInfusion.getIsUndo());
                 deviceOperator.setInfusionId(lastInfusion.getId());
                 BusInfusionModifyEntity infusionModify = infusionModifyService.getOne(new QueryWrapper<BusInfusionModifyEntity>().lambda().eq(BusInfusionModifyEntity::getInfusionId, lastInfusion.getId()).orderByDesc(BusInfusionModifyEntity::getModifyTime).last("LIMIT 1"));
                 if(infusionModify!=null){

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

@@ -1,7 +1,6 @@
 package com.coffee.bus.registry.device;
 
 import com.coffee.bus.entity.BusDeviceRunningEntity;
-import com.coffee.bus.enums.DeviceAlarmEnum;
 import com.coffee.bus.enums.DeviceStatusEnum;
 import com.coffee.bus.registry.Operator;
 
@@ -186,18 +185,6 @@ public interface DeviceOperator extends Operator {
      */
     String getClassification();
 
-    /**
-     * 获取当前输注状态下是否撤泵
-     * @return
-     */
-    Boolean getUndo();
-
-    /**
-     * 设置撤泵信息
-     * @param undo
-     */
-    void setUndo(Boolean undo);
-
     /**
      * 获取设备最新上传数据时间
      * @return

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

@@ -215,7 +215,7 @@ public class LocalBusClinicService extends BaseService<BusClinicMapper, BusClini
      * @return boolean
      */
     public boolean isFinished(String clinicId) {
-        return this.getById(clinicId).getFinished();
+        return Boolean.TRUE.equals(Optional.ofNullable(this.getById(clinicId)).orElse(new BusClinicEntity()).getFinished());
     }
 
     /**

+ 106 - 49
coffee-system/src/main/java/com/coffee/bus/service/LocalBusInfusionHistoryService.java

@@ -4,6 +4,7 @@ import cn.hutool.core.collection.CollectionUtil;
 import cn.hutool.core.util.StrUtil;
 import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
 import cn.hutool.extra.spring.SpringUtil;
+import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper;
 import com.baomidou.mybatisplus.core.conditions.update.UpdateWrapper;
 import com.baomidou.mybatisplus.core.toolkit.Wrappers;
 import com.coffee.aliyun.utils.Constants;
@@ -14,12 +15,14 @@ import com.coffee.bus.enums.PatientAlarmEnum;
 import com.coffee.bus.listener.event.infusion.InfusionCreateEvent;
 import com.coffee.bus.listener.event.infusion.InfusionUpdateEvent;
 import com.coffee.bus.mapper.BusInfusionHistoryMapper;
+import com.coffee.bus.registry.device.DeviceOperator;
 import com.coffee.bus.registry.device.DeviceRegistry;
 import com.coffee.bus.registry.patient.PatientOperator;
 import com.coffee.bus.registry.patient.PatientRegistry;
 import com.coffee.bus.service.dto.ManualUndoConfig;
 import com.coffee.bus.service.dto.UndoDeviceConfig;
 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;
@@ -49,7 +52,7 @@ public class LocalBusInfusionHistoryService extends BaseService<BusInfusionHisto
 
     @Autowired
     @Lazy
-    private PatientRegistry patientRegistry;
+    private DeviceRegistry deviceRegistry;
 
     @Autowired
     @Lazy
@@ -221,44 +224,50 @@ public class LocalBusInfusionHistoryService extends BaseService<BusInfusionHisto
      */
     @Transactional(rollbackFor = Exception.class)
     public void undo(ManualUndoConfig manualUndoConfig, boolean finishClinic) {
-        if(finishClinic){
-            List<String> infusionIds = manualUndoConfig.getInfusionIds();
-            if(CollectionUtil.isNotEmpty(infusionIds)){
-                /****************将撤泵记录存入到泵的使用历史记录中***************/
-                //无泵监护,不需要监护输注数据
-                if(Boolean.TRUE.equals(manualUndoConfig.getMonitorType())){
-                    if(!finishClinic){
-                        BusPatientEntity patient = patientService.getOne(new QueryWrapper<BusPatientEntity>().lambda()
-                                .eq(BusPatientEntity::getCode, manualUndoConfig.getPatientCode())
-                                .eq(StrUtil.isNotEmpty(manualUndoConfig.getTenantId()), BusPatientEntity::getTenantId, manualUndoConfig.getTenantId()));
-                        //去除主泵id
-                        infusionIds=infusionIds.stream().filter(id->!id.equals(patient.getInfusionId())).collect(Collectors.toList());
-                    }
-                    //输注结束,更新撤泵信息
-                    if(CollectionUtil.isNotEmpty(infusionIds)){
-                        UndoDeviceConfig undo = manualUndoConfig.getUndo();
-                        this.update(new UpdateWrapper<BusInfusionHistoryEntity>().lambda()
-                                .in(BusInfusionHistoryEntity::getId,infusionIds)
-                                .set(BusInfusionHistoryEntity::getIsUndo,true)
-                                .set(BusInfusionHistoryEntity::getUndoBy,undo.getUndoBy())
-                                .set(BusInfusionHistoryEntity::getUndoTime,undo.getUndoTime())
-                                .set(BusInfusionHistoryEntity::getDestroyer,undo.getDestroyer())
-                                .set(BusInfusionHistoryEntity::getWitnesses,undo.getWitnesses()));
-                    }
+        List<String> deviceIds = manualUndoConfig.getDeviceIds();
+        List<String> infusionIds = manualUndoConfig.getInfusionIds();
+        if(CollectionUtil.isEmpty(deviceIds)&&CollectionUtil.isEmpty(infusionIds)){
+            throw new CustomException("撤泵未选择设备");
+        }
+        if(CollectionUtil.isEmpty(manualUndoConfig.getInfusionIds())){
+            infusionIds =deviceIds.stream().map(deviceRegistry::getOperator).map(DeviceOperator::getInfusionId).collect(Collectors.toList());
+        }
+        if(!finishClinic){
+            //无泵监护,不需要监护输注数据
+            if(Boolean.TRUE.equals(manualUndoConfig.getMonitorType())){
+                BusPatientEntity patient = patientService.getOne(new QueryWrapper<BusPatientEntity>().lambda()
+                        .eq(BusPatientEntity::getCode, manualUndoConfig.getPatientCode())
+                        .eq(StrUtil.isNotEmpty(manualUndoConfig.getTenantId()), BusPatientEntity::getTenantId, manualUndoConfig.getTenantId()));
+                //去除主泵id
+                infusionIds=infusionIds.stream().filter(id->!id.equals(patient.getInfusionId())).collect(Collectors.toList());
+                //输注结束,更新撤泵信息
+                if(CollectionUtil.isNotEmpty(infusionIds)){
+                    UndoDeviceConfig undo = manualUndoConfig.getUndo();
+                    this.update(new UpdateWrapper<BusInfusionHistoryEntity>().lambda()
+                            .in(BusInfusionHistoryEntity::getId,infusionIds)
+                            .set(BusInfusionHistoryEntity::getIsUndo,true)
+                            .set(BusInfusionHistoryEntity::getUndoBy,undo.getUndoBy())
+                            .set(BusInfusionHistoryEntity::getUndoTime,undo.getUndoTime())
+                            .set(BusInfusionHistoryEntity::getDestroyer,undo.getDestroyer())
+                            .set(BusInfusionHistoryEntity::getWitnesses,undo.getWitnesses()));
                 }
             }
-        }else {
+
+        } else {
+            //结束临床
             UndoDeviceConfig undo = manualUndoConfig.getUndo();
-            this.update(new UpdateWrapper<BusInfusionHistoryEntity>()
-                    .lambda()
-                    .eq(BusInfusionHistoryEntity::getFinished,false)
-                    .eq(BusInfusionHistoryEntity::getPatientCode,manualUndoConfig.getPatientCode())
-                    .eq(StrUtil.isNotEmpty(manualUndoConfig.getTenantId()),BusInfusionHistoryEntity::getTenantId,manualUndoConfig.getTenantId())
-                    .set(BusInfusionHistoryEntity::getIsUndo,true)
-                    .set(BusInfusionHistoryEntity::getUndoBy,undo.getUndoBy())
-                    .set(BusInfusionHistoryEntity::getDestroyer,undo.getDestroyer())
-                    .set(BusInfusionHistoryEntity::getUndoTime,undo.getUndoTime())
-                    .set(BusInfusionHistoryEntity::getUndoTime,undo.getUndoTime()));
+            if(Boolean.TRUE.equals(manualUndoConfig.getMonitorType())){
+                this.update(new UpdateWrapper<BusInfusionHistoryEntity>()
+                        .lambda()
+                        .eq(BusInfusionHistoryEntity::getFinished,false)
+                        .eq(BusInfusionHistoryEntity::getPatientCode,manualUndoConfig.getPatientCode())
+                        .eq(StrUtil.isNotEmpty(manualUndoConfig.getTenantId()),BusInfusionHistoryEntity::getTenantId,manualUndoConfig.getTenantId())
+                        .set(BusInfusionHistoryEntity::getIsUndo,true)
+                        .set(BusInfusionHistoryEntity::getUndoBy,undo.getUndoBy())
+                        .set(BusInfusionHistoryEntity::getDestroyer,undo.getDestroyer())
+                        .set(BusInfusionHistoryEntity::getUndoTime,undo.getUndoTime())
+                        .set(BusInfusionHistoryEntity::getUndoTime,undo.getUndoTime()));
+            }
             clinicService.finish(manualUndoConfig.getClinicId(),manualUndoConfig.getTenantId());
         }
     }
@@ -275,33 +284,81 @@ public class LocalBusInfusionHistoryService extends BaseService<BusInfusionHisto
     }
 
     public BusInfusionHistoryEntity lastInfusion(String deviceId) {
-        return this.getOne(new QueryWrapper<BusInfusionHistoryEntity>().lambda().eq(BusInfusionHistoryEntity::getDeviceId,deviceId).orderByDesc(BusInfusionHistoryEntity::getStartTime).last("limit 1"));
+        return this.getOne(new QueryWrapper<BusInfusionHistoryEntity>().lambda()
+                .eq(BusInfusionHistoryEntity::getDeviceId,deviceId)
+                .orderByDesc(BusInfusionHistoryEntity::getStartTime)
+                .last("limit 1"));
     }
 
     /**
-     * 描述: 处理非正常关机的输注信息
+     * 描述: 输注设备被占用处理
      * @author lifang
      * @date 2022/5/31 9:11
-     * @param abnormalInfusion
+     * @param lastInfusion 设备被占用前最后一条输注数据
      * @return void
      */
-    public BusInfusionHistoryEntity handleAbnormalInfusion(BusInfusionHistoryEntity abnormalInfusion) {
+    @Transactional(rollbackFor = Exception.class)
+    public BusInfusionHistoryEntity deviceOccupation(BusInfusionHistoryEntity lastInfusion) {
         List<BusInfusionHistoryEntity> infusionHistories = this.list(new QueryWrapper<BusInfusionHistoryEntity>().lambda()
                 .eq(BusInfusionHistoryEntity::getFinished, false)
-                .eq(BusInfusionHistoryEntity::getPatientCode, abnormalInfusion.getPatientCode())
-                .eq(BusInfusionHistoryEntity::getTenantId, abnormalInfusion.getTenantId()));
-        BusInfusionHistoryEntity lastInfusion=null;
-        if(CollectionUtil.isNotEmpty(infusionHistories)){
-            lastInfusion = infusionHistories.stream().max(Comparator.comparing(BusInfusionHistoryEntity::getStartTime)).orElse(null);
-        }
+                .eq(BusInfusionHistoryEntity::getPatientCode, lastInfusion.getPatientCode())
+                .eq(BusInfusionHistoryEntity::getTenantId, lastInfusion.getTenantId()));
         int size = CollectionUtil.size(infusionHistories);
+        if(size>0){
+            lastInfusion = infusionHistories.stream().max(Comparator.comparing(BusInfusionHistoryEntity::getStartTime)).orElseGet(null);
+        }
+
         patientService.update(new UpdateWrapper<BusPatientEntity>().lambda()
-                .eq(BusPatientEntity::getCode,abnormalInfusion.getPatientCode())
-                .eq(BusPatientEntity::getTenantId,abnormalInfusion.getTenantId())
-                .set(lastInfusion!=null,BusPatientEntity::getInfusionId,lastInfusion.getId())
+                .eq(BusPatientEntity::getCode,lastInfusion.getPatientCode())
+                .eq(BusPatientEntity::getTenantId,lastInfusion.getTenantId())
+                .set(BusPatientEntity::getInfusionId,lastInfusion.getId())
                 .set(size==0,BusPatientEntity::getAlarm, PatientAlarmEnum.DEVICE_NONE)
                 .set(size==1,BusPatientEntity::getAlarm, PatientAlarmEnum.NONE)
                 .set(size>1,BusPatientEntity::getAlarm, PatientAlarmEnum.DEVICE_REPEAT));
         return lastInfusion;
     }
+
+    /**
+     * 描述: 对设备关机进行处理
+     * @author lifang
+     * @date 2022/5/31 11:32
+     * @param tenantId 医院id
+     * @param patientCode 病号
+     * @param infusionId 关机的输注id
+     * @return void
+     */
+    @Transactional(rollbackFor = Exception.class)
+    public BusInfusionHistoryEntity deviceShutDown(String infusionId, String patientCode, String tenantId) {
+        List<BusInfusionHistoryEntity> infusionHistories = this.list(new QueryWrapper<BusInfusionHistoryEntity>().lambda()
+                .ne(BusInfusionHistoryEntity::getId,infusionId)
+                .eq(BusInfusionHistoryEntity::getFinished, false)
+                .eq(BusInfusionHistoryEntity::getPatientCode, patientCode)
+                .eq(BusInfusionHistoryEntity::getTenantId,tenantId));
+        int size = CollectionUtil.size(infusionHistories);
+        BusInfusionHistoryEntity lastInfusion=null;
+        LambdaUpdateWrapper<BusPatientEntity> updateWrapper = new UpdateWrapper<BusPatientEntity>().lambda()
+                .eq(BusPatientEntity::getCode, patientCode)
+                .eq(BusPatientEntity::getTenantId, tenantId)
+                .set(size == 0, BusPatientEntity::getAlarm, PatientAlarmEnum.DEVICE_NONE)
+                .set(size == 1, BusPatientEntity::getAlarm, PatientAlarmEnum.NONE)
+                .set(size > 1, BusPatientEntity::getAlarm, PatientAlarmEnum.DEVICE_REPEAT);
+        if(size>0){
+            infusionHistories
+                    .stream()
+                    .max(Comparator.comparing(BusInfusionHistoryEntity::getStartTime))
+                    .map(infusion->{
+                        updateWrapper    .set(BusPatientEntity::getInfusionId, infusion.getId());
+                        return infusion;
+                    });
+        }
+        patientService.update(updateWrapper);
+        return lastInfusion;
+    }
+
+    public BusInfusionHistoryEntity findInfusion(String deviceId, String classification) {
+        return this.getOne(new QueryWrapper<BusInfusionHistoryEntity>()
+                .lambda()
+                .eq(BusInfusionHistoryEntity::getDeviceId,deviceId).eq(BusInfusionHistoryEntity::getClassification,classification)
+                .last("limit 1"));
+    }
 }

+ 1 - 7
coffee-system/src/main/java/com/coffee/bus/service/LocalBusPatientService.java

@@ -365,13 +365,9 @@ public class LocalBusPatientService extends BaseService<BusPatientMapper, BusPat
     @Transactional(rollbackFor = Exception.class)
     public void shift(DeviceShiftConfig shiftConfig) {
         PatientOperator patientOperator = patientRegistry.getOperator(shiftConfig.getTenantId(), shiftConfig.getPatientCode());
-        String bindDeviceId = patientOperator.getBindDeviceId();
         List<String> replicaDeviceIds = shiftConfig.getReplicaDeviceIds();
         String masterDeviceId = shiftConfig.getMasterDeviceId();
-        if (masterDeviceId.equals(bindDeviceId)) {
-            //主泵未发生切换
-            return;
-        }
+
         BusInfusionHistoryEntity masterInfusion = infusionHistoryService.lastInfusion(masterDeviceId);
 
         //病患绑定主泵信息
@@ -384,8 +380,6 @@ public class LocalBusPatientService extends BaseService<BusPatientMapper, BusPat
         replicaDeviceIds.stream()
                 .map(deviceRegistry::getOperator).forEach(deviceOperator->{
             deviceOperator.setMaster(false);
-            //切换后也标注为暂时撤泵,即后续该泵发来的数据不再做主副泵切换的判断
-            deviceOperator.setUndo(true);
         });
 
         patientOperator.setBindDeviceId(shiftConfig.getMasterDeviceId());

+ 1 - 0
coffee-system/src/main/java/com/coffee/bus/service/dto/ClinicAnalClinicRecord.java

@@ -86,6 +86,7 @@ public class ClinicAnalClinicRecord  implements Serializable {
         clinicRecord.setWeight(clinic.getWeight());
         clinicRecord.setHeight(clinic.getHeight());
         clinicRecord.setBedNo(clinic.getBedNo());
+        clinicRecord.setWard(clinic.getWard());
         clinicRecord.setAsa(clinic.getAsa());
         clinicRecord.setFormula(clinic.getFormula());
         clinicRecord.setAnaDoctor(clinic.getAnaDoctor());

+ 10 - 6
coffee-system/src/main/java/com/coffee/bus/service/dto/ManualUndoConfig.java

@@ -20,16 +20,16 @@ import java.util.*;
  */
 @Data
 @ApiModel("手动结束临床配置")
-@AllArgsConstructor(staticName = "of")
 @NoArgsConstructor
+@AllArgsConstructor
 public class ManualUndoConfig implements Serializable {
 
-//    @ApiModelProperty("进行撤泵的所有运行数据id")
-//    @NotNull(message = "撤泵输注号不能为空")
-//    private List<String> deviceIds;
+    @ApiModelProperty("进行撤泵的所有设备号")
+    @NotNull(message = "撤泵设备号不能为空")
+    private List<String> deviceIds;
 
-    @ApiModelProperty("进行撤泵的输注id")
-    @NotNull(message = "撤泵输注号不能为空")
+    @ApiModelProperty(value = "进行撤泵的输注id,仅系统内部使用",hidden = true)
+    @JsonIgnore
     private List<String> infusionIds;
 
     @ApiModelProperty("撤泵病号")
@@ -49,4 +49,8 @@ public class ManualUndoConfig implements Serializable {
     @ApiModelProperty("撤泵配置")
     @NotNull(message = "撤泵配置不能为空")
     private UndoDeviceConfig undo;
+
+    public static ManualUndoConfig of(List<String> infusionIds, String patientCode,String clinicId,String tenantId,Boolean monitorType,UndoDeviceConfig undo){
+        return new ManualUndoConfig(null,infusionIds,patientCode,clinicId,tenantId,monitorType,undo);
+    }
 }

+ 0 - 1
coffee-system/src/main/java/com/coffee/bus/utils/WsPublishUtils.java

@@ -32,7 +32,6 @@ import java.io.Serializable;
 @Slf4j
 public class WsPublishUtils implements Serializable{
     private final LocalBusPatientService patientService;
-    private final LocalBusClinicService clinicService;
     private final RedissonUtil redissonUtil;
 
     private void publish(String topic,TopicMessage msg){

+ 44 - 15
coffee-system/src/main/java/com/coffee/bus/websocket/listener/DeviceInfoListener.java

@@ -23,10 +23,12 @@ import lombok.extern.slf4j.Slf4j;
 import org.springframework.context.event.EventListener;
 import org.springframework.stereotype.Component;
 import org.springframework.transaction.annotation.Transactional;
-import org.tio.utils.crypto.Md5;
 
 import java.util.*;
 import java.util.List;
+import java.util.concurrent.CompletableFuture;
+import java.util.concurrent.Executor;
+import java.util.concurrent.TimeUnit;
 import java.util.function.Supplier;
 
 /**
@@ -59,8 +61,8 @@ public class DeviceInfoListener {
 
     private final WsPublishUtils wsPublishUtils;
 
-    private final LocalBusDeviceService deviceService;
 
+    private final Executor executor;
     private final HospitalManagerRegister hospitalManagerRegister;
 
 
@@ -113,13 +115,23 @@ public class DeviceInfoListener {
                     wsPublishUtils.publishPatientMonitor(device.getPatientCode(),device.getTenantId());
                     wsPublishUtils.publishMonitorStateCount(device.getTenantId());
                 }
-                if (Boolean.TRUE.equals(device.isInfusionModify())) {
+                if (Boolean.TRUE.equals(device.isInfusionModify())||DeviceStatusEnum.Shutdown.equals(device.getRunState())) {
                     wsPublishUtils.publishDeviceNone(device.getTenantId());
                     wsPublishUtils.publishDeviceRepeat(device.getTenantId());
                 }
                 if (Boolean.TRUE.equals(device.isResetClinic())) {
                     wsPublishUtils.publishMonitorTotalCount(device.getTenantId());
                 }
+                if(device.isNewInfusion()){
+                    CompletableFuture.runAsync(()->{
+                        hospitalManagerRegister.get(device.getTenantId()).getScriptSession()
+                                .asyncGetPatientInfo(device.getPatientCode(),10, TimeUnit.SECONDS,false);
+                    },executor)
+                            .exceptionally(t->{
+                                log.error("新的输注产生后,拉取病号【{}】信息失败,失败原因:",device.getPatientCode(),t);
+                                return null;
+                            });
+                }
                 return null;
             });
 
@@ -136,6 +148,7 @@ public class DeviceInfoListener {
         device.setMonitorType(true);
         device.setUploadTime(device.getUploadTime()==null?new Date():device.getUploadTime());
 
+        device.setStartTime(deviceOperator.getStartTime());
         device.setTenantId(deviceOperator.getTenantId());
 
     }
@@ -168,9 +181,9 @@ public class DeviceInfoListener {
                         .set(runningInfusionCount>0,BusPatientEntity::getAlarm,PatientAlarmEnum.DEVICE_REPEAT)
                         .set(runningInfusionCount==0,BusPatientEntity::getAlarm,PatientAlarmEnum.NONE));
                 BusInfusionHistoryEntity lastInfusion = infusionHistoryService.lastInfusion(deviceId);
-                if(ObjectUtil.notEqual(device.getPatientCode(),lastInfusion.getPatientCode())&&!DeviceStatusEnum.Shutdown.equals(lastInfusion.getRunState())){
-                    //处理非正常关机的输注信息,返回处理后的该病号绑定的正常输注信息
-                    BusInfusionHistoryEntity normalInfusion = infusionHistoryService.handleAbnormalInfusion(lastInfusion);
+                if(lastInfusion!=null&&ObjectUtil.notEqual(device.getPatientCode(),lastInfusion.getPatientCode())){
+                    //输注设备被占用
+                    BusInfusionHistoryEntity normalInfusion = infusionHistoryService.deviceOccupation(lastInfusion);
                     if(normalInfusion!=null){
                         patientRegistry.getOperator(lastInfusion.getTenantId(), lastInfusion.getPatientCode()).setBindDeviceId(normalInfusion.getDeviceId());
                         suppliers.add(()->{
@@ -181,6 +194,7 @@ public class DeviceInfoListener {
                 }
                 if(clinicFinished){
                     clinicService.resetClinic(device.getClinicId());
+                    device.setResetClinic(true);
                 }
                 device.setMaster(true);
                 suppliers.add(()->{
@@ -218,16 +232,26 @@ public class DeviceInfoListener {
             device.setMaster(true);
         }
         if (isNewInFusion(device.getDeviceId(),device.getClassification())) {
-            //结束其余输注信息
-            infusionHistory.setId(IdWorker.getIdStr());
-            infusionHistory.setFinished(false);
-            device.setNewInfusion(true);
-            infusionHistoryService.update(new UpdateWrapper<BusInfusionHistoryEntity>().lambda()
-                    .eq(BusInfusionHistoryEntity::getPatientCode,device.getPatientCode())
-                    .eq(BusInfusionHistoryEntity::getTenantId,device.getTenantId())
-                    .eq(BusInfusionHistoryEntity::getFinished,false)
-                    .set(BusInfusionHistoryEntity::getFinished,true));
+            BusInfusionHistoryEntity exist=infusionHistoryService.findInfusion(device.getDeviceId(),device.getClassification());
+            if(exist==null){
+                infusionHistory.setId(IdWorker.getIdStr());
+                infusionHistory.setFinished(false);
+                infusionHistory.setStartTime(device.getUploadTime());
+                device.setNewInfusion(true);
+                //结束其余输注信息
+                infusionHistoryService.update(new UpdateWrapper<BusInfusionHistoryEntity>().lambda()
+                        .eq(BusInfusionHistoryEntity::getDeviceId,device.getDeviceId())
+                        .eq(BusInfusionHistoryEntity::getTenantId,device.getTenantId())
+                        .eq(BusInfusionHistoryEntity::getFinished,false)
+                        .set(BusInfusionHistoryEntity::getFinished,true));
+            }else {
+                device.setNewInfusion(false);
+                infusionHistory.setStartTime(device.getStartTime());
+                infusionHistory.setId(exist.getId());
+            }
         }else {
+            device.setNewInfusion(false);
+            infusionHistory.setStartTime(device.getStartTime());
             infusionHistory.setId(originInfusionId);
         }
         device.setInfusionId(infusionHistory.getId());
@@ -235,6 +259,7 @@ public class DeviceInfoListener {
             if(device.isNewInfusion()){
                 deviceOperator.setInfusionId(device.getInfusionId());
                 deviceOperator.setClassification(device.getClassification());
+                deviceOperator.setStartTime(infusionHistory.getStartTime());
             }
             return null;
         });
@@ -275,6 +300,10 @@ public class DeviceInfoListener {
                 infusionModifyService.save(modify);
             }
             device.setInfusionModifyId(modify.getId());
+            if (DeviceStatusEnum.Shutdown.equals(device.getRunState())) {
+                //设备关机后,查看用户是否存在其他正在进行的输注
+                infusionHistoryService.deviceShutDown(device.getInfusionId(),device.getPatientCode(),device.getTenantId());
+            }
         }
     }
 

+ 3 - 3
coffee-system/src/main/java/com/coffee/bus/websocket/listener/HisInfoListener.java

@@ -5,6 +5,7 @@ import cn.hutool.json.JSONUtil;
 import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
 import com.coffee.bus.entity.BusClinicEntity;
 import com.coffee.bus.entity.BusHospitalEntity;
+import com.coffee.bus.entity.BusPatientEntity;
 import com.coffee.bus.hospital.his.strategy.HisStrategyHandler;
 import com.coffee.bus.hospital.his.strategy.HisStrategyManager;
 import com.coffee.bus.hospital.his.strategy.HisStrategyManagerRegister;
@@ -18,6 +19,7 @@ import org.springframework.stereotype.Component;
 import org.springframework.transaction.annotation.Transactional;
 import org.springframework.transaction.interceptor.TransactionAspectSupport;
 
+import java.util.Comparator;
 import java.util.List;
 
 /**
@@ -37,6 +39,7 @@ public class HisInfoListener {
 
     private final HisStrategyManagerRegister managerRegister;
 
+    private final LocalBusPatientService patientService;
     @Async
     @EventListener
     @Transactional(rollbackFor = Exception.class)
@@ -52,9 +55,6 @@ public class HisInfoListener {
             BusHospitalEntity hospital = hospitalService.getById(hospitalId);
             HisStrategyManager<? extends HisStrategyHandler> hisStrategyManager = managerRegister.get(hospital.getStrategy());
 
-            //todo 处理病人信息
-
-
             List<BusClinicEntity> target = clinicService.list(new QueryWrapper<BusClinicEntity>().lambda()
                     .eq(BusClinicEntity::getPatientCode, patientCode).eq(BusClinicEntity::getTenantId, hospitalId)
                     .eq(BusClinicEntity::getMonitorType, true));

+ 352 - 343
coffee-system/src/main/resources/mapper/bus/BusPatientMapper.xml

@@ -1,104 +1,104 @@
 <?xml version="1.0" encoding="UTF-8"?>
-    <!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
-    <mapper namespace="com.coffee.bus.mapper.BusPatientMapper">
+<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
+<mapper namespace="com.coffee.bus.mapper.BusPatientMapper">
 
-        <resultMap id="repeatDeviceResult" type="com.coffee.bus.entity.PatientDeviceRepeatDomain">
-            <result column="name" property="name"/>
-            <result column="gender" property="gender"/>
-            <result column="code" property="code"/>
-            <result column="age" property="age"/>
-            <result column="ward" property="ward"/>
-            <result column="bed_no" property="bedNo"/>
-            <result column="clinic_name" property="clinicName"/>
-            <result column="device_id" property="deviceId"/>
-            <result column="device_alias" property="deviceAlias"/>
-            <result column="device_run_state" property="deviceRunState"/>
-            <result column="clinic_id" property="clinicId"/>
-            <result column="device_alarm" property="deviceAlarm" />
-            <result column="infusion_start_time" property="infusionStartTime"/>
-            <result column="infusion_id" property="infusionId"/>
-            <result column="master_infusion_id" property="masterInfusionId"/>
-        </resultMap>
+    <resultMap id="repeatDeviceResult" type="com.coffee.bus.entity.PatientDeviceRepeatDomain">
+        <result column="name" property="name"/>
+        <result column="gender" property="gender"/>
+        <result column="code" property="code"/>
+        <result column="age" property="age"/>
+        <result column="ward" property="ward"/>
+        <result column="bed_no" property="bedNo"/>
+        <result column="clinic_name" property="clinicName"/>
+        <result column="device_id" property="deviceId"/>
+        <result column="device_alias" property="deviceAlias"/>
+        <result column="device_run_state" property="deviceRunState"/>
+        <result column="clinic_id" property="clinicId"/>
+        <result column="device_alarm" property="deviceAlarm" />
+        <result column="infusion_start_time" property="infusionStartTime"/>
+        <result column="infusion_id" property="infusionId"/>
+        <result column="master_infusion_id" property="masterInfusionId"/>
+    </resultMap>
 
-        <resultMap id="monitorResult" type="com.coffee.bus.service.dto.PatientMonitorResult">
-            <result column="patient_name" property="patientName"/>
-            <result column="patient_code" property="patientCode"/>
-            <result column="patient_age" property="patientAge"/>
-            <result column="gender" property="gender"/>
-            <result column="infusion_id" property="infusionId"/>
-            <result column="patient_alarm" property="patientAlarm"/>
-            <result column="classification" property="classification"/>
-            <result column="data_num" property="dataNum"/>
-            <result column="device_id" property="deviceId"/>
-            <result column="device_alias" property="deviceAlias"/>
-            <result column="clinic_id" property="clinicId"/>
-            <result column="patient_gender" property="gender"/>
-            <result column="infusion_finished" property="infusionFinished"/>
-            <result column="ward" property="ward"/>
-            <result column="bed_no" property="bedNo"/>
-            <result column="total_dose" property="totalDose"/>
-            <result column="first_dose" property="firstDose"/>
-            <result column="remain_dose" property="remainDose"/>
-            <result column="input_dose" property="inputDose"/>
-            <result column="append_dose" property="appendDose"/>
-            <result column="append_lock_time" property="appendLockTime"/>
-            <result column="max_dose" property="maxDose"/>
-            <result column="self_control_count" property="selfControlCount"/>
-            <result column="self_control_lock_time" property="selfControlLockTime"/>
-            <result column="pca_valid_count" property="pcaValidCount"/>
-            <result column="pca_invalid_count" property="pcaInvalidCount"/>
-            <result column="pca_total_count" property="pcaTotalCount"/>
-            <result column="continue_dose" property="continueDose"/>
-            <result column="pulse_dose" property="pulseDose"/>
-            <result column="pulse_first_lock_time" property="pulseFirstLockTime"/>
-            <result column="pulse_lock_time" property="pulseLockTime"/>
-            <result column="flow_up_cycle" property="flowUpCycle"/>
-            <result column="flow_down_cycle" property="flowDownCycle"/>
-            <result column="flow_count" property="flowCount"/>
-            <result column="flow_up_limit" property="flowUpLimit"/>
-            <result column="flow_down_limit" property="flowDownLimit"/>
-            <result column="flow_adjust_rate" property="flowAdjustRate"/>
-            <result column="run_state" property="deviceRunState"/>
-            <result column="electric_quantity" property="electricQuantity"/>
-            <result column="warn_flow" property="warnFlow"/>
-            <result column="warn_analgesic_poor" property="warnAnalgesicPoor"/>
-            <result column="warn_low_battery" property="warnLowBattery"/>
-            <result column="warn_will_finished" property="warnWillFinished"/>
-            <result column="device_alarm" property="deviceAlarm"/>
-            <result column="infusion_start_time" property="infusionStartTime"/>
-            <result column="remark" property="remark"/>
-            <result column="device_type" property="deviceType"/>
-            <result column="anal_type" property="analType"/>
-            <result column="ana_doctor" property="anaDoctor"/>
-            <result column="ana_type" property="anaType"/>
-            <result column="surgery_doctor" property="surgeryDoctor"/>
-            <result column="surgery_name" property="surgeryName"/>
-            <result column="finished" property="clinicFinished"/>
-            <result column="monitor_end_time" property="monitorEndTime"/>
-            <result column="monitor_start_time" property="monitorStartTime"/>
-        </resultMap>
+    <resultMap id="monitorResult" type="com.coffee.bus.service.dto.PatientMonitorResult">
+        <result column="patient_name" property="patientName"/>
+        <result column="patient_code" property="patientCode"/>
+        <result column="patient_age" property="patientAge"/>
+        <result column="gender" property="gender"/>
+        <result column="infusion_id" property="infusionId"/>
+        <result column="patient_alarm" property="patientAlarm"/>
+        <result column="classification" property="classification"/>
+        <result column="data_num" property="dataNum"/>
+        <result column="device_id" property="deviceId"/>
+        <result column="device_alias" property="deviceAlias"/>
+        <result column="clinic_id" property="clinicId"/>
+        <result column="patient_gender" property="gender"/>
+        <result column="infusion_finished" property="infusionFinished"/>
+        <result column="ward" property="ward"/>
+        <result column="bed_no" property="bedNo"/>
+        <result column="total_dose" property="totalDose"/>
+        <result column="first_dose" property="firstDose"/>
+        <result column="remain_dose" property="remainDose"/>
+        <result column="input_dose" property="inputDose"/>
+        <result column="append_dose" property="appendDose"/>
+        <result column="append_lock_time" property="appendLockTime"/>
+        <result column="max_dose" property="maxDose"/>
+        <result column="self_control_count" property="selfControlCount"/>
+        <result column="self_control_lock_time" property="selfControlLockTime"/>
+        <result column="pca_valid_count" property="pcaValidCount"/>
+        <result column="pca_invalid_count" property="pcaInvalidCount"/>
+        <result column="pca_total_count" property="pcaTotalCount"/>
+        <result column="continue_dose" property="continueDose"/>
+        <result column="pulse_dose" property="pulseDose"/>
+        <result column="pulse_first_lock_time" property="pulseFirstLockTime"/>
+        <result column="pulse_lock_time" property="pulseLockTime"/>
+        <result column="flow_up_cycle" property="flowUpCycle"/>
+        <result column="flow_down_cycle" property="flowDownCycle"/>
+        <result column="flow_count" property="flowCount"/>
+        <result column="flow_up_limit" property="flowUpLimit"/>
+        <result column="flow_down_limit" property="flowDownLimit"/>
+        <result column="flow_adjust_rate" property="flowAdjustRate"/>
+        <result column="run_state" property="deviceRunState"/>
+        <result column="electric_quantity" property="electricQuantity"/>
+        <result column="warn_flow" property="warnFlow"/>
+        <result column="warn_analgesic_poor" property="warnAnalgesicPoor"/>
+        <result column="warn_low_battery" property="warnLowBattery"/>
+        <result column="warn_will_finished" property="warnWillFinished"/>
+        <result column="device_alarm" property="deviceAlarm"/>
+        <result column="infusion_start_time" property="infusionStartTime"/>
+        <result column="remark" property="remark"/>
+        <result column="device_type" property="deviceType"/>
+        <result column="anal_type" property="analType"/>
+        <result column="ana_doctor" property="anaDoctor"/>
+        <result column="ana_type" property="anaType"/>
+        <result column="surgery_doctor" property="surgeryDoctor"/>
+        <result column="surgery_name" property="surgeryName"/>
+        <result column="finished" property="clinicFinished"/>
+        <result column="monitor_end_time" property="monitorEndTime"/>
+        <result column="monitor_start_time" property="monitorStartTime"/>
+    </resultMap>
 
-        <resultMap id="deviceNone" type="com.coffee.bus.service.dto.PatientDeviceNoneResult">
-            <result column="clinic_id" property="clinicId"/>
-            <result column="name" property="name"/>
-            <result column="gender" property="gender"/>
-            <result column="code" property="code"/>
-            <result column="age" property="age"/>
-            <result column="ward" property="ward"/>
-            <result column="bed_no" property="bedNo"/>
-            <result column="surgery_name" property="surgeryName"/>
-            <result column="weight" property="weight"/>
-            <result column="height" property="height"/>
-            <result column="ana_doctor" property="anaDoctor"/>
-            <result column="ana_type" property="anaType"/>
-            <result column="anal_type" property="analType"/>
-            <result column="surgery_doctor" property="surgeryDoctor"/>
-            <result column="asa" property="asa"/>
-            <result column="formula" property="formula" typeHandler="com.baomidou.mybatisplus.extension.handlers.FastjsonTypeHandler"/>
-            <result column="finished" property="finished"/>
-            <result column="config_person" property="configPerson"/>
-        </resultMap>
-        <select id="selectRepeatDevice" resultMap="repeatDeviceResult">
+    <resultMap id="deviceNone" type="com.coffee.bus.service.dto.PatientDeviceNoneResult">
+        <result column="clinic_id" property="clinicId"/>
+        <result column="name" property="name"/>
+        <result column="gender" property="gender"/>
+        <result column="code" property="code"/>
+        <result column="age" property="age"/>
+        <result column="ward" property="ward"/>
+        <result column="bed_no" property="bedNo"/>
+        <result column="surgery_name" property="surgeryName"/>
+        <result column="weight" property="weight"/>
+        <result column="height" property="height"/>
+        <result column="ana_doctor" property="anaDoctor"/>
+        <result column="ana_type" property="anaType"/>
+        <result column="anal_type" property="analType"/>
+        <result column="surgery_doctor" property="surgeryDoctor"/>
+        <result column="asa" property="asa"/>
+        <result column="formula" property="formula" typeHandler="com.baomidou.mybatisplus.extension.handlers.FastjsonTypeHandler"/>
+        <result column="finished" property="finished"/>
+        <result column="config_person" property="configPerson"/>
+    </resultMap>
+    <select id="selectRepeatDevice" resultMap="repeatDeviceResult">
                      SELECT
              p.code as code,
              p.infusion_id as master_infusion_id,
@@ -121,7 +121,7 @@
             join  (SELECT * FROM bus_clinic WHERE finished=0 ) AS c ON  c.`patient_code`=p.code;
         </select>
 
-        <select id="selectNoneDevice" resultMap="deviceNone">
+    <select id="selectNoneDevice" resultMap="deviceNone">
             SELECT
              p.code as code,
              c.id as clinic_id,
@@ -147,267 +147,276 @@
             order by c.monitor_start_time desc;
         </select>
 
-        <select id="selectMonitor" resultMap="monitorResult" parameterType="com.coffee.bus.service.dto.PatientMonitorQuery">
-            select
-            p.`code` as patient_code,
-            p.alarm as patient_alarm,
-            i.id as infusion_id,
-            i.device_id as device_id,
-            i.clinic_id as clinic_id,
-            i.classification as classification,
-            i.data_number as data_number,
-            i.total_dose as total_dose,
-            i.first_dose as first_dose,
-            i.remain_dose as remain_dose,
-            i.input_dose as input_dose,
-            i.append_dose as append_dose,
-            i.append_lock_time as append_lock_time,
-            i.max_dose as max_dose,
-            i.finished as infusion_finished,
-            i.electric_quantity as electric_quantity,
-            i.warn_flow as warn_flow,
-            i.self_control_count as self_control_count,
-            i.self_control_lock_time as self_control_lock_time,
-            i.pca_valid_count as pca_valid_count,
-            i.pca_invalid_count as pca_invalid_count,
-            i.pca_total_count as pca_total_count,
-            i.continue_dose as continue_dose,
-            i.pulse_dose as pulse_dose,
-            i.pulse_lock_time as pulse_lock_time,
-            i.pulse_first_lock_time as pulse_first_lock_time,
-            i.flow_up_cycle as flow_up_cycle,
-            i.flow_down_cycle as flow_down_cycle,
-            i.flow_count as flow_count,
-            i.flow_up_limit as flow_up_limit,
-            i.flow_down_limit as flow_down_limit,
-            i.flow_adjust_rate as flow_adjust_rate,
-            i.run_state as run_state,
-            i.warn_will_finished as warn_will_finished,
-            i.warn_analgesic_poor as warn_analgesic_poor,
-            i.warn_low_battery as warn_low_battery,
-            i.alarm as device_alarm,
-            i.start_time as infusion_start_time,
-            i.remark as remark,
-            i.type as device_type,
-            d.alias as device_alias,
-            c.patient_gender as patient_gender,
-            c.`patient_name` as patient_name,
-            c.finished as finished,
-            c.monitor_start_time as monitor_start_time,
-            c.end_time as monitor_end_time,
-            c.ana_doctor as ana_doctor,
-            c.patient_age as patient_age,
-            c.ana_type as ana_type,
-            c.anal_type as anal_type,
-            c.surgery_doctor as surgery_doctor,
-            c.surgery_name as surgery_name,
-            c.ward as ward,
-            c.bed_no as bed_no
-            from
-            (select * from bus_patient
-            <where>
-                <if test="query.tenantId!=null">
-                    and tenant_id=#{query.tenantId}
-                </if>
-            </where>
-            )
-            as p
-            join
-            (select * from bus_infusion_history
-            <where>
-                is_undo='0'
-                <if test="query.wards != null and query.wards.size > 0">
-                    and ward in
-                    <foreach item="ward" index="index" collection="query.wards" open="(" separator="," close=")">
-                        #{ward, jdbcType=VARCHAR}
-                    </foreach>
-                </if>
-                <if test="query.types != null and query.types.size > 0">
-                    and type in
-                    <foreach item="type" index="index" collection="query.types" open="(" separator="," close=")">
-                        #{type, jdbcType=VARCHAR}
+    <select id="selectMonitor" resultMap="monitorResult" parameterType="com.coffee.bus.service.dto.PatientMonitorQuery">
+        select
+        p.`code` as patient_code,
+        p.alarm as patient_alarm,
+        i.id as infusion_id,
+        i.device_id as device_id,
+        i.clinic_id as clinic_id,
+        i.classification as classification,
+        i.data_number as data_number,
+        i.total_dose as total_dose,
+        i.first_dose as first_dose,
+        i.remain_dose as remain_dose,
+        i.input_dose as input_dose,
+        i.append_dose as append_dose,
+        i.append_lock_time as append_lock_time,
+        i.max_dose as max_dose,
+        i.finished as infusion_finished,
+        i.electric_quantity as electric_quantity,
+        i.warn_flow as warn_flow,
+        i.self_control_count as self_control_count,
+        i.self_control_lock_time as self_control_lock_time,
+        i.pca_valid_count as pca_valid_count,
+        i.pca_invalid_count as pca_invalid_count,
+        i.pca_total_count as pca_total_count,
+        i.continue_dose as continue_dose,
+        i.pulse_dose as pulse_dose,
+        i.pulse_lock_time as pulse_lock_time,
+        i.pulse_first_lock_time as pulse_first_lock_time,
+        i.flow_up_cycle as flow_up_cycle,
+        i.flow_down_cycle as flow_down_cycle,
+        i.flow_count as flow_count,
+        i.flow_up_limit as flow_up_limit,
+        i.flow_down_limit as flow_down_limit,
+        i.flow_adjust_rate as flow_adjust_rate,
+        i.run_state as run_state,
+        i.warn_will_finished as warn_will_finished,
+        i.warn_analgesic_poor as warn_analgesic_poor,
+        i.warn_low_battery as warn_low_battery,
+        i.alarm as device_alarm,
+        i.start_time as infusion_start_time,
+        i.remark as remark,
+        i.type as device_type,
+        d.alias as device_alias,
+        c.patient_gender as patient_gender,
+        c.`patient_name` as patient_name,
+        c.finished as finished,
+        c.monitor_start_time as monitor_start_time,
+        c.end_time as monitor_end_time,
+        c.ana_doctor as ana_doctor,
+        c.patient_age as patient_age,
+        c.ana_type as ana_type,
+        c.anal_type as anal_type,
+        c.surgery_doctor as surgery_doctor,
+        c.surgery_name as surgery_name,
+        c.ward as ward,
+        c.bed_no as bed_no
+        from
+        (select * from bus_patient
+        <where>
+            <if test="query.tenantId!=null">
+                and tenant_id=#{query.tenantId}
+            </if>
+        </where>
+        )
+        as p
+        join
+        (select * from bus_infusion_history
+        <where>
+            is_undo='0'
+            <if test="query.wards != null and query.wards.size > 0">
+                and ward in
+                <foreach item="ward" index="index" collection="query.wards" open="(" separator="," close=")">
+                    #{ward, jdbcType=VARCHAR}
+                </foreach>
+            </if>
+            <if test="query.types != null and query.types.size > 0">
+                and type in
+                <foreach item="type" index="index" collection="query.types" open="(" separator="," close=")">
+                    #{type, jdbcType=VARCHAR}
+                </foreach>
+            </if>
+            <choose>
+                <when test="query.deviceStatus != null and query.deviceStatus.size > 0">
+                    and (
+                    run_state in
+                    <foreach item="status" index="index" collection="query.deviceStatus" open="(" separator=","
+                             close=")">
+                        #{status, jdbcType=VARCHAR}
                     </foreach>
-                </if>
-                <choose>
-                    <when test="query.deviceStatus != null and query.deviceStatus.size > 0">
-                        and (
-                        run_state in
-                        <foreach item="status" index="index" collection="query.deviceStatus" open="(" separator=","
+                    <if test="query.deviceAlarms != null and query.deviceAlarms.size > 0">
+                        or alarm in
+                        <foreach item="alarm" index="index" collection="query.deviceAlarms" open="(" separator=","
                                  close=")">
-                            #{status, jdbcType=VARCHAR}
+                            #{alarm, jdbcType=VARCHAR}
                         </foreach>
-                        <if test="query.deviceAlarms != null and query.deviceAlarms.size > 0">
-                            or alarm in
-                            <foreach item="alarm" index="index" collection="query.deviceAlarms" open="(" separator=","
-                                     close=")">
-                                #{alarm, jdbcType=VARCHAR}
-                            </foreach>
-                        </if>
-                        <if test="query.infusionFinished == true">
-                            or finished=#{query.infusionFinished}
-                        </if>
-                        )
-                    </when>
-                    <otherwise>
-                        <if test="query.deviceAlarms != null and query.deviceAlarms.size > 0">
-                            and alarm in
-                            <foreach item="alarm" index="index" collection="query.deviceAlarms" open="(" separator="," close=")">
-                                #{alarm, jdbcType=VARCHAR}
-                            </foreach>
-                        </if>
-                    </otherwise>
-                </choose>
-                <choose>
-                    <when test="query.warnWillFinished != false or query.warnAnalgesicPoor != false or  query.warnLowBattery != false">
-                        and (
-                        <choose>
-                            <when test="query.warnWillFinished != false">warn_will_finished=1</when>
-                            <otherwise>warn_will_finished!=1</otherwise>
-                        </choose>
-                        <if test="query.warnAnalgesicPoor != false">or warn_analgesic_poor=1 </if>
-                        <if test="query.warnLowBattery != false"> or warn_low_battery=1 </if>
-                        <if test="query.warnFlow !=null">
-                            or warn_flow= #{query.warnFlow}
-                        </if>
-                        )
-                    </when>
-                    <otherwise>
-                        <if test="query.warnFlow !=null">
-                            and warn_flow= #{query.warnFlow}
-                        </if>
-                    </otherwise>
-                </choose>
-            </where>
-            ) as i on p.infusion_id=i.id
-            left join (select device_id,alias from bus_device) as d on d.device_id=i.device_id
-            join (select * from bus_clinic
-            <where>
-                finished=0
-                <if test="query.timeRange != null and query.timeRange.size >0">
-                    and monitor_start_time &gt; #{query.timeRange[0]} and  monitor_start_time &lt; #{query.timeRange[1]}
-                </if>
-            </where>
-            ) c on p.clinic_id=c.id
-            <if test="query.bedNo!=null || query.name!=null || query.code!=null || query.anaDoctor!=null || query.surgeName!=null ||query.gender!=null ||query.anaType!=null">
-                <where>
-                    (1=0
-                    <if test="query.bedNo!=null">
-                        or i.bed_no LIKE concat('%', #{query.bedNo}, '%')
                     </if>
-                    <if test="query.name!=null">
-                        or c.`name` LIKE concat('%', #{query.name}, '%')
+                    <if test="query.infusionFinished == true">
+                        or finished=#{query.infusionFinished}
                     </if>
-                    <if test="query.code!=null">
-                        or p.`code` LIKE concat('%', #{query.code}, '%')
-                    </if>
-                    <if test="query.anaDoctor!=null">
-                        or c.`ana_doctor` like concat('%', #{query.anaDoctor}, '%')
+                    )
+                </when>
+                <otherwise>
+                    <if test="query.deviceAlarms != null and query.deviceAlarms.size > 0">
+                        and alarm in
+                        <foreach item="alarm" index="index" collection="query.deviceAlarms" open="(" separator="," close=")">
+                            #{alarm, jdbcType=VARCHAR}
+                        </foreach>
                     </if>
-                    <if test="query.surgeName!=null">
-                        or c.`surgery_name` like concat('%',#{query.surgeName}, '%')
+                </otherwise>
+            </choose>
+            <choose>
+                <when test="query.warnWillFinished != false or query.warnAnalgesicPoor != false or  query.warnLowBattery != false">
+                    and (
+                    <choose>
+                        <when test="query.warnWillFinished != false">warn_will_finished=1</when>
+                        <otherwise>warn_will_finished!=1</otherwise>
+                    </choose>
+                    <if test="query.warnAnalgesicPoor != false">or warn_analgesic_poor=1 </if>
+                    <if test="query.warnLowBattery != false"> or warn_low_battery=1 </if>
+                    <if test="query.warnFlow !=null">
+                        or warn_flow= #{query.warnFlow}
                     </if>
-                    <if test="query.gender!=null">
-                        or c.gender LIKE concat('%', #{query.gender}, '%')
+                    )
+                </when>
+                <otherwise>
+                    <if test="query.warnFlow !=null">
+                        and warn_flow= #{query.warnFlow}
                     </if>
-                    <if test="query.anaType!=null">
-                        or c.ana_type LIKE concat('%', #{query.anaType}, '%')
-                    </if>)
-                </where>
+                </otherwise>
+            </choose>
+        </where>
+        ) as i on p.infusion_id=i.id
+        left join (select device_id,alias from bus_device) as d on d.device_id=i.device_id
+        join (select * from bus_clinic
+        <where>
+            finished=0
+            <if test="query.timeRange != null and query.timeRange.size >0">
+                and monitor_start_time &gt; #{query.timeRange[0]} and  monitor_start_time &lt; #{query.timeRange[1]}
             </if>
-            order by c.monitor_start_time desc
-        </select>
-
-
-        <select id="findByPatientCode" resultMap="monitorResult">
-            select
-            p.alarm as patient_alarm,
-            p.`code` as patient_code,
-            i.device_id as device_id,
-            i.clinic_id as clinic_id,
-            i.classification as classification,
-            i.total_dose as total_dose,
-            i.first_dose as first_dose,
-            i.remain_dose as remain_dose,
-            i.input_dose as input_dose,
-            i.append_dose as append_dose,
-            i.append_lock_time as append_lock_time,
-            i.max_dose as max_dose,
-            i.electric_quantity as electric_quantity,
-            i.warn_flow as warn_flow,
-            i.self_control_count as self_control_count,
-            i.self_control_lock_time as self_control_lock_time,
-            i.pca_valid_count as pca_valid_count,
-            i.pca_invalid_count as pca_invalid_count,
-            i.pca_total_count as pca_total_count,
-            i.continue_dose as continue_dose,
-            i.pulse_dose as pulse_dose,
-            i.pulse_lock_time as pulse_lock_time,
-            i.pulse_first_lock_time as pulse_first_lock_time,
-            i.flow_up_cycle as flow_up_cycle,
-            i.flow_down_cycle as flow_down_cycle,
-            i.flow_count as flow_count,
-            i.flow_up_limit as flow_up_limit,
-            i.flow_down_limit as flow_down_limit,
-            i.flow_adjust_rate as flow_adjust_rate,
-            i.run_state as run_state,
-            i.warn_will_finished as warn_will_finished,
-            i.warn_analgesic_poor as warn_analgesic_poor,
-            i.warn_low_battery as warn_low_battery,
-            i.alarm as device_alarm,
-            i.start_time as infusion_start_time,
-            i.remark as remark,
-            i.type as device_type,
-            d.alias as device_alias,
-            c.ward as ward,
-            c.bed_no as bed_no,
-            c.finished as finished,
-            c.`patient_name` as patient_name,
-            c.patient_gender as gender,
-            c.monitor_start_time as monitor_start_time,
-            c.end_time as monitor_end_time,
-            c.ana_doctor as ana_doctor,
-            c.patient_age as patient_age,
-            c.ana_type as ana_type,
-            c.anal_type as anal_type,
-            c.surgery_doctor as surgery_doctor,
-            c.surgery_name as surgery_name
-            from
-            (select * from bus_patient
+            <if test="query.tenantId!=null">
+                and tenant_id=#{query.tenantId}
+            </if>
+        </where>
+        ) c on p.clinic_id=c.id
+        <if test="query.bedNo!=null || query.name!=null || query.code!=null || query.anaDoctor!=null || query.surgeName!=null ||query.gender!=null ||query.anaType!=null">
             <where>
-                <if test="tenantId!=null">
-                    and tenant_id=#{tenantId}
+                (1=0
+                <if test="query.bedNo!=null">
+                    or i.bed_no LIKE concat('%', #{query.bedNo}, '%')
                 </if>
-                <if test="patientCode!=null">
-                    and code=#{patientCode}
+                <if test="query.name!=null">
+                    or c.`patient_name` LIKE concat('%', #{query.name}, '%')
                 </if>
-            </where>
-            )
-            as p
-            join
-              bus_infusion_history as i on p.infusion_id=i.id
-            join (select device_id,alias from bus_device) as d on d.device_id=i.device_id
-            left join bus_clinic c on p.clinic_id=c.id
-            limit 1
-        </select>
-
-        <select id="selectAlarmCount" resultType="long">
-            select count(1) from bus_patient as p
-            join (select * from bus_clinic
-            <where>
-                finished=0
-                <if test="tenantId!=null">
-                    and tenant_id=#{tenantId}
+                <if test="query.code!=null">
+                    or p.`code` LIKE concat('%', #{query.code}, '%')
                 </if>
-            </where>
-            ) as c on p.code=c.patient_code
-            <where>
-                <if test="alarmValue!=null">
-                    and p.alarm=#{alarmValue}
+                <if test="query.anaDoctor!=null">
+                    or c.`ana_doctor` like concat('%', #{query.anaDoctor}, '%')
+                </if>
+                <if test="query.surgeName!=null">
+                    or c.`surgery_name` like concat('%',#{query.surgeName}, '%')
+                </if>
+                <if test="query.gender!=null">
+                    or c.gender LIKE concat('%', #{query.gender}, '%')
                 </if>
+                <if test="query.anaType!=null">
+                    or c.ana_type LIKE concat('%', #{query.anaType}, '%')
+                </if>)
             </where>
-        </select>
+        </if>
+        order by c.monitor_start_time desc
+    </select>
+
+
+    <select id="findByPatientCode" resultMap="monitorResult">
+        select
+        p.alarm as patient_alarm,
+        p.`code` as patient_code,
+        i.device_id as device_id,
+        i.clinic_id as clinic_id,
+        i.classification as classification,
+        i.total_dose as total_dose,
+        i.first_dose as first_dose,
+        i.remain_dose as remain_dose,
+        i.input_dose as input_dose,
+        i.append_dose as append_dose,
+        i.append_lock_time as append_lock_time,
+        i.max_dose as max_dose,
+        i.electric_quantity as electric_quantity,
+        i.warn_flow as warn_flow,
+        i.self_control_count as self_control_count,
+        i.self_control_lock_time as self_control_lock_time,
+        i.pca_valid_count as pca_valid_count,
+        i.pca_invalid_count as pca_invalid_count,
+        i.pca_total_count as pca_total_count,
+        i.continue_dose as continue_dose,
+        i.pulse_dose as pulse_dose,
+        i.pulse_lock_time as pulse_lock_time,
+        i.pulse_first_lock_time as pulse_first_lock_time,
+        i.flow_up_cycle as flow_up_cycle,
+        i.flow_down_cycle as flow_down_cycle,
+        i.flow_count as flow_count,
+        i.flow_up_limit as flow_up_limit,
+        i.flow_down_limit as flow_down_limit,
+        i.flow_adjust_rate as flow_adjust_rate,
+        i.run_state as run_state,
+        i.warn_will_finished as warn_will_finished,
+        i.warn_analgesic_poor as warn_analgesic_poor,
+        i.warn_low_battery as warn_low_battery,
+        i.alarm as device_alarm,
+        i.start_time as infusion_start_time,
+        i.remark as remark,
+        i.type as device_type,
+        d.alias as device_alias,
+        c.ward as ward,
+        c.bed_no as bed_no,
+        c.finished as finished,
+        c.`patient_name` as patient_name,
+        c.patient_gender as gender,
+        c.monitor_start_time as monitor_start_time,
+        c.end_time as monitor_end_time,
+        c.ana_doctor as ana_doctor,
+        c.patient_age as patient_age,
+        c.ana_type as ana_type,
+        c.anal_type as anal_type,
+        c.surgery_doctor as surgery_doctor,
+        c.surgery_name as surgery_name
+        from
+        (select * from bus_patient
+        <where>
+            <if test="tenantId!=null">
+                and tenant_id=#{tenantId}
+            </if>
+            <if test="patientCode!=null">
+                and code=#{patientCode}
+            </if>
+        </where>
+        )
+        as p
+        join
+        bus_infusion_history as i on p.infusion_id=i.id
+        join (select device_id,alias from bus_device) as d on d.device_id=i.device_id
+        left join bus_clinic c on p.clinic_id=c.id
+        limit 1
+    </select>
+
+    <select id="selectAlarmCount" resultType="long">
+        select count(1) from (select * from bus_patient
+        <where>
+            <if test="tenantId!=null">
+                and tenant_id=#{tenantId}
+            </if>
+        </where>
+        ) as p
+        join (select * from bus_clinic
+        <where>
+            finished=0
+            <if test="tenantId!=null">
+                and tenant_id=#{tenantId}
+            </if>
+        </where>
+        ) as c on p.code=c.patient_code
+        <where>
+            <if test="alarmValue!=null">
+                and p.alarm=#{alarmValue}
+            </if>
+        </where>
+    </select>
 
     <select id="monitorTotalCount" resultType="long">
         select count(1) from (select * from bus_patient where tenant_id=#{tenantId}) as p JOIN (select * from bus_clinic where finished=0 and tenant_id=#{tenantId}) as c on p.clinic_id=c.id
     </select>
-    </mapper>
+</mapper>