A17404李放 3 năm trước cách đây
mục cha
commit
317513aebf
38 tập tin đã thay đổi với 635 bổ sung300 xóa
  1. 1 1
      coffee-admin/src/test/java/com/coffee/admin/BusHospitalTest.java
  2. 2 0
      coffee-common/src/main/java/com/coffee/common/Constants.java
  3. 0 124
      coffee-common/src/main/java/com/coffee/common/config/websocket/DefaultWebSocketMsgHandler.java
  4. 28 0
      coffee-common/src/main/java/com/coffee/common/config/websocket/HospitalCodeCheck.java
  5. 0 1
      coffee-common/src/main/java/com/coffee/common/config/websocket/MessageResponse.java
  6. 0 1
      coffee-common/src/main/java/com/coffee/common/config/websocket/MessagingRequest.java
  7. 20 3
      coffee-common/src/main/java/com/coffee/common/crud/controller/BaseSaveController.java
  8. 1 0
      coffee-common/src/main/java/com/coffee/common/exception/ExecuteResult.java
  9. 1 1
      coffee-system/src/main/java/com/coffee/bus/bean/Script.java
  10. 66 0
      coffee-system/src/main/java/com/coffee/bus/config/mybaits/WardHandler.java
  11. 40 41
      coffee-system/src/main/java/com/coffee/bus/controller/BusClinicController.java
  12. 2 1
      coffee-system/src/main/java/com/coffee/bus/controller/BusDeviceController.java
  13. 8 0
      coffee-system/src/main/java/com/coffee/bus/controller/BusDeviceManualController.java
  14. 11 9
      coffee-system/src/main/java/com/coffee/bus/controller/BusHospitalController.java
  15. 43 0
      coffee-system/src/main/java/com/coffee/bus/controller/BusInfusionHistoryController.java
  16. 7 1
      coffee-system/src/main/java/com/coffee/bus/controller/BusPatientController.java
  17. 0 4
      coffee-system/src/main/java/com/coffee/bus/entity/BusClinicEntity.java
  18. 3 2
      coffee-system/src/main/java/com/coffee/bus/entity/BusHospitalEntity.java
  19. 3 2
      coffee-system/src/main/java/com/coffee/bus/hospital/HospitalManager.java
  20. 6 51
      coffee-system/src/main/java/com/coffee/bus/hospital/his/HisScriptSession.java
  21. 2 0
      coffee-system/src/main/java/com/coffee/bus/hospital/his/strategy/HisStrategyEnum.java
  22. 1 0
      coffee-system/src/main/java/com/coffee/bus/hospital/his/strategy/all/EqualsStrategyHandler.java
  23. 0 32
      coffee-system/src/main/java/com/coffee/bus/hospital/script/PythonParse.java
  24. 56 2
      coffee-system/src/main/java/com/coffee/bus/service/LocalBusDeviceManualService.java
  25. 17 6
      coffee-system/src/main/java/com/coffee/bus/service/LocalBusHospitalService.java
  26. 1 1
      coffee-system/src/main/java/com/coffee/bus/service/LocalBusPatientService.java
  27. 54 2
      coffee-system/src/main/java/com/coffee/bus/service/constant/LocalBusConMixService.java
  28. 1 1
      coffee-system/src/main/java/com/coffee/bus/service/dto/ClinicQuery.java
  29. 34 0
      coffee-system/src/main/java/com/coffee/bus/service/dto/HospitalScriptResult.java
  30. 4 0
      coffee-system/src/main/java/com/coffee/bus/service/dto/PatientMonitorResult.java
  31. 6 2
      coffee-system/src/main/java/com/coffee/bus/web/handler/CheckTimeHandler.java
  32. 184 0
      coffee-system/src/main/java/com/coffee/bus/websocket/DefaultWebSocketMsgHandler.java
  33. 3 5
      coffee-system/src/main/java/com/coffee/bus/websocket/HisConnectionHandler.java
  34. 12 1
      coffee-system/src/main/java/com/coffee/bus/websocket/WebSocketCloseHandler.java
  35. 5 0
      coffee-system/src/main/java/com/coffee/bus/websocket/listener/DeviceInfoListener.java
  36. 2 0
      coffee-system/src/main/java/com/coffee/system/entity/SysMenu.java
  37. 1 1
      coffee-system/src/main/resources/mapper/bus/BusDeviceHistoryMapper.xml
  38. 10 5
      coffee-system/src/main/resources/mapper/bus/BusPatientMapper.xml

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

@@ -45,7 +45,7 @@ public class BusHospitalTest {
         busHospitalEntity.setName("人民医院");
         busHospitalEntity.setTelephone("18339543637");
         busHospitalEntity.setEmail("493216081@qq.com");
-        busHospitalController.add(busHospitalEntity);
+//        busHospitalController.add(busHospitalEntity);
     }
 
     @Test

+ 2 - 0
coffee-common/src/main/java/com/coffee/common/Constants.java

@@ -19,6 +19,8 @@ public class Constants {
      */
     public static final String LOGIN_USER_KEY = "user";
 
+    public static final String HOSPITAL_ID = "hospital_id";
+
     /**
      * redis缓存,项目统一前缀
      */

+ 0 - 124
coffee-common/src/main/java/com/coffee/common/config/websocket/DefaultWebSocketMsgHandler.java

@@ -1,124 +0,0 @@
-package com.coffee.common.config.websocket;
-
-import cn.dev33.satoken.stp.StpUtil;
-import cn.hutool.core.collection.CollectionUtil;
-import cn.hutool.core.util.StrUtil;
-import cn.hutool.json.JSONUtil;
-import com.coffee.common.Constants;
-import com.coffee.common.bo.LoginUser;
-import com.coffee.common.config.websocket.handler.WsHandler;
-import com.coffee.common.result.R;
-import lombok.AllArgsConstructor;
-import lombok.extern.slf4j.Slf4j;
-import org.springframework.boot.autoconfigure.AutoConfigureAfter;
-import org.springframework.data.redis.core.RedisTemplate;
-import org.springframework.stereotype.Component;
-import org.tio.core.ChannelContext;
-import org.tio.core.Tio;
-import org.tio.http.common.HttpRequest;
-import org.tio.http.common.HttpResponse;
-import org.tio.websocket.common.WsRequest;
-import org.tio.websocket.common.WsResponse;
-import org.tio.websocket.server.handler.IWsMsgHandler;
-import java.util.*;
-import java.util.stream.Collectors;
-
-@Component
-@Slf4j
-@AllArgsConstructor
-@AutoConfigureAfter(RedisTemplate.class)
-public class DefaultWebSocketMsgHandler implements IWsMsgHandler {
-    private final List<WsHandler> messageHandlers;
-    @Override
-    public HttpResponse handshake(HttpRequest httpRequest, HttpResponse httpResponse, ChannelContext channelContext) {
-        return httpResponse;
-    }
-
-    @Override
-    public void onAfterHandshaked(HttpRequest httpRequest, HttpResponse httpResponse, ChannelContext channelContext) throws Exception {
-        String authorization = httpRequest.getParam("Authorization");
-        if(log.isDebugEnabled()){
-            log.debug("websocket 握手成功,开始进行权限校验,Authorization:{}",authorization);
-        }
-        if(StrUtil.isNullOrUndefined(authorization)){
-            Tio.send(channelContext,WsResponse.fromText(JSONUtil.toJsonStr(R.fail("授权失败")),"utf-8"));
-            //给返回信息一些时间 todo
-            channelContext.setClosed(true);
-            return;
-        }
-        Object result = StpUtil.getTokenSessionByToken(authorization).get(Constants.LOGIN_USER_KEY);
-        if(null==result){
-            Tio.send(channelContext,WsResponse.fromText(JSONUtil.toJsonStr(R.fail("授权失败")),"utf-8"));
-            if(log.isDebugEnabled()){
-                log.debug("Authorization:{},鉴权失败",authorization);
-            }
-            unbind(channelContext);
-            Thread.sleep(50);
-            channelContext.setClosed(true);
-            return;
-        }
-        Tio.bindToken(channelContext, JSONUtil.toJsonStr(authorization));
-        LoginUser loginUser = (LoginUser)result;
-        channelContext.set(Constants.LOGIN_USER_KEY,loginUser);
-        Tio.send(channelContext,WsResponse.fromText(JSONUtil.toJsonStr(R.success("连接成功")),"utf-8"));
-
-    }
-
-    @Override
-    public Object onBytes(WsRequest wsRequest, byte[] bytes, ChannelContext channelContext){
-        return null;
-    }
-
-    @Override
-    public Object onClose(WsRequest wsRequest, byte[] bytes, ChannelContext channelContext) {
-        messageHandlers.forEach(wsHandler -> wsHandler.close(channelContext));
-        return null;
-    }
-
-    @Override
-    public Object onText(WsRequest wsRequest, String message, ChannelContext channelContext) {
-        if (StrUtil.isEmpty(message)) {
-            unbind(channelContext);
-            channelContext.setClosed(true);
-            return null;
-        }
-        //心跳请求 todo
-        if("ping".equals(message.trim().toLowerCase())){
-            Tio.send(channelContext,WsResponse.fromText("pong","utf-8"));
-            return null;
-        }
-        try {
-            synchronized (channelContext){
-            if(log.isDebugEnabled()){
-                log.debug("websocket 接收到消息,message:{},token:{},userId:{}",message,channelContext.getToken(),JSONUtil.toJsonStr(channelContext.get(Constants.LOGIN_USER_KEY)));
-            }
-            MessagingRequest messagingRequest = JSONUtil.toBean(message, MessagingRequest.class);
-
-            messagingRequest.validate();
-            List<WsHandler> collect = messageHandlers
-                    .parallelStream()
-                    .filter(handler -> messagingRequest.getId().equals(handler.getId()))
-                    .collect(Collectors.toList());
-            //传入格式错误,不支持该订阅id
-            if(CollectionUtil.isEmpty(collect)){
-                unbind(channelContext);
-                channelContext.setClosed(true);
-                return null;
-            }
-
-                collect.forEach(handler->handler.onMessage(messagingRequest,channelContext));
-            }
-        }catch (Exception e){
-            log.warn("websocket 接收到异常请求,token:{},message:{},userId:{}",channelContext.getToken(),message,JSONUtil.toJsonStr(channelContext.get(Constants.LOGIN_USER_KEY)));
-            unbind(channelContext);
-            channelContext.setClosed(true);
-        }
-
-        return null;
-    }
-
-    private void unbind(ChannelContext channelContext){
-        Tio.unbindToken(channelContext);
-        Tio.unbindUser(channelContext);
-    }
-}

+ 28 - 0
coffee-common/src/main/java/com/coffee/common/config/websocket/HospitalCodeCheck.java

@@ -0,0 +1,28 @@
+package com.coffee.common.config.websocket;
+
+/**
+ * @author lifang
+ * @version 1.0.0
+ * @ClassName HospitalCodeCheck.java
+ * @Description 医院编码检测
+ * @createTime 2022年05月26日 15:31:00
+ */
+public interface HospitalCodeCheck {
+    /**
+     * 描述: 检测该医院编码是否存在
+     * @author lifang
+     * @date 2022/5/26 15:31
+     * @param code 医院编码
+     * @return boolean
+     */
+    boolean isExistCode(String code);
+
+    /**
+     * 描述: 获取医院编码对应的医院id
+     * @author lifang
+     * @date 2022/5/26 15:31
+     * @param code 医院编码
+     * @return boolean
+     */
+    String getHospitalId(String code);
+}

+ 0 - 1
coffee-common/src/main/java/com/coffee/common/config/websocket/MessageResponse.java

@@ -1,6 +1,5 @@
 package com.coffee.common.config.websocket;
 
-import cn.hutool.json.JSON;
 import lombok.AllArgsConstructor;
 import lombok.Data;
 

+ 0 - 1
coffee-common/src/main/java/com/coffee/common/config/websocket/MessagingRequest.java

@@ -1,7 +1,6 @@
 package com.coffee.common.config.websocket;
 
 import cn.hutool.core.util.StrUtil;
-import cn.hutool.json.JSONUtil;
 import lombok.Data;
 
 import java.util.*;

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

@@ -3,8 +3,11 @@ package com.coffee.common.crud.controller;
 import com.baomidou.mybatisplus.core.mapper.Mapper;
 import com.coffee.common.crud.BaseService;
 import com.coffee.common.entity.GenericEntity;
+import com.coffee.common.entity.TenantGenericEntity;
 import com.coffee.common.result.R;
 import io.swagger.annotations.ApiOperation;
+import io.swagger.annotations.ApiParam;
+import org.simpleframework.xml.Attribute;
 import org.springframework.validation.annotation.Validated;
 import org.springframework.web.bind.annotation.*;
 
@@ -28,23 +31,37 @@ public interface BaseSaveController<E,K extends Serializable> extends
 
     @PostMapping("/_batch")
     @ApiOperation(value = "批量新增数据")
-    default R add(@RequestBody @Validated(GenericEntity.Insert.class) List<E> payload) {
+    default R add(@RequestAttribute("tenantId")@ApiParam(hidden = true) Serializable tenantId, @RequestBody @Validated(GenericEntity.Insert.class) List<E> payload) {
         saveAuth();
+        payload.forEach(p->{
+            if(p instanceof TenantGenericEntity){
+                TenantGenericEntity entity= (TenantGenericEntity) p;
+                entity.setTenantId(tenantId);
+            }
+        });
         return getService().saveBatch(payload)?R.success():R.fail("数据新增失败");
     }
 
     @PostMapping("/add")
     @ApiOperation(value = "新增单个数据,并返回新增后的数据.")
-    default R add(@RequestBody @Validated(GenericEntity.Insert.class)E payload) {
+    default R add(@RequestAttribute("tenantId")@ApiParam(hidden = true) Serializable tenantId,@RequestBody @Validated(GenericEntity.Insert.class)E payload) {
         saveAuth();
+        if(payload instanceof TenantGenericEntity){
+            TenantGenericEntity entity= (TenantGenericEntity) payload;
+            entity.setTenantId(tenantId);
+        }
         return getService().save(payload)?R.success(payload):R.fail("数据新增失败");
     }
 
 
     @PostMapping("/edit")
     @ApiOperation(value = "根据ID修改数据")
-    default R update(@RequestBody @Validated(GenericEntity.Update.class)E payload) {
+    default R update(@RequestAttribute("tenantId")@ApiParam(hidden = true) String tenantId,@RequestBody @Validated(GenericEntity.Update.class)E payload) {
         editAuth();
+        if(payload instanceof TenantGenericEntity){
+            TenantGenericEntity entity= (TenantGenericEntity) payload;
+            entity.setTenantId(tenantId);
+        }
         return getService().updateById(payload)?R.success(payload):R.fail("更新失败");
     }
 }

+ 1 - 0
coffee-common/src/main/java/com/coffee/common/exception/ExecuteResult.java

@@ -65,6 +65,7 @@ public class ExecuteResult {
 
     public void setException(Exception exception) {
         this.exception = exception;
+        message=exception.toString();
     }
 
     public long getUseTime() {

+ 1 - 1
coffee-system/src/main/java/com/coffee/bus/bean/Script.java

@@ -15,7 +15,7 @@ import java.io.Serializable;
 @Data
 public class Script implements Serializable {
     @JsonIgnore
-    private String id;
+    private String id="python";
     private String content;
     /**
      * json xml soap

+ 66 - 0
coffee-system/src/main/java/com/coffee/bus/config/mybaits/WardHandler.java

@@ -0,0 +1,66 @@
+package com.coffee.bus.config.mybaits;
+
+import cn.hutool.extra.spring.SpringUtil;
+import com.coffee.bus.service.constant.LocalBusConMixService;
+import lombok.extern.slf4j.Slf4j;
+import org.apache.ibatis.type.*;
+import org.springframework.web.context.request.RequestContextHolder;
+import org.springframework.web.context.request.ServletRequestAttributes;
+
+import java.sql.CallableStatement;
+import java.sql.ResultSet;
+import java.sql.SQLException;
+
+import static org.springframework.web.context.request.RequestAttributes.SCOPE_REQUEST;
+
+/**
+ * @author lifang
+ * @version 1.0.0
+ * @ClassName WardHandler.java
+ * @Description 病区处理器
+ * @createTime 2022年05月26日 21:06:00
+ */
+@Slf4j
+@MappedTypes({String.class})
+@MappedJdbcTypes(JdbcType.VARCHAR)
+public class WardHandler extends StringTypeHandler {
+    private LocalBusConMixService conMixService;
+
+
+    @Override
+    public String getNullableResult(ResultSet rs, String columnName) throws SQLException {
+        init();
+        return conMixService.getWard(getTenantId(),rs.getString(columnName));
+    }
+
+    @Override
+    public String getNullableResult(ResultSet rs, int columnIndex) throws SQLException {
+        init();
+        return conMixService.getWard(getTenantId(),rs.getString(columnIndex));
+    }
+
+    @Override
+    public String getNullableResult(CallableStatement cs, int columnIndex) throws SQLException {
+        init();
+        return conMixService.getWard(getTenantId(),cs.getString(columnIndex));
+    }
+
+    private String getTenantId(){
+        //判断是否为request请求
+        ServletRequestAttributes request = (ServletRequestAttributes) RequestContextHolder.getRequestAttributes();
+        if(request==null){
+            return "";
+        }
+        Object tenantId = request.getAttribute("tenantId", SCOPE_REQUEST);
+        if(tenantId==null){
+            return "";
+        }
+        return  String.valueOf(tenantId);
+    }
+
+    private void init(){
+        if(conMixService==null){
+            conMixService= SpringUtil.getBean(LocalBusConMixService.class);
+        }
+    }
+}

+ 40 - 41
coffee-system/src/main/java/com/coffee/bus/controller/BusClinicController.java

@@ -78,47 +78,46 @@ public class BusClinicController {
         //填充评价记录
         result.setEvaluations(evaluationService.list(new QueryWrapper<BusEvaluationEntity>().lambda().eq(BusEvaluationEntity::getClinicId,clinicId).orderByAsc(BusEvaluationEntity::getEvaluateTime)));
 
-        //填充输注记录
-        List<BusInfusionHistoryEntity> infusionHistories = infusionHistoryService.list(new QueryWrapper<BusInfusionHistoryEntity>().lambda()
-                .eq(BusInfusionHistoryEntity::getClinicId, clinicId)
-                .orderByAsc(BusInfusionHistoryEntity::getStartTime));
-
-        result.fillUndoInfo(infusionHistories);
-
-        //添加设备别名
-        Map<String, List<BusInfusionHistoryEntity>> infusionByDeviceId = infusionHistories.stream().collect(Collectors.groupingBy(BusInfusionHistoryEntity::getDeviceId));
-        infusionByDeviceId.forEach((deviceId,infusions)->{
-            String alias = deviceRegistry.getOperator(deviceId).getAlias();
-            infusions.forEach(infusion->infusion.setAlias(alias));
-        });
-
-        List<String> infusionIds = infusionHistories.stream().map(BusInfusionHistoryEntity::getId).collect(Collectors.toList());
-        List<BusInfusionModifyEntity> infusionModifies = infusionModifyService.list(new QueryWrapper<BusInfusionModifyEntity>().lambda()
-                .in(BusInfusionModifyEntity::getInfusionId, infusionIds));
-
-        result.fillInfusionRecords(infusionHistories,infusionModifies);
-
-        List<BusDeviceHistoryEntity> deviceHistories = deviceHistoryService.list(new QueryWrapper<BusDeviceHistoryEntity>()
-                .lambda()
-                .select(BusDeviceHistoryEntity::getInfusionId,BusDeviceHistoryEntity::getPcaValidCount,BusDeviceHistoryEntity::getInfusionModifyId,
-                        BusDeviceHistoryEntity::getPcaInvalidCount,BusDeviceHistoryEntity::getInputDose,BusDeviceHistoryEntity::getUploadTime)
-                .in(BusDeviceHistoryEntity::getInfusionId, infusionIds)
-                .eq(BusDeviceHistoryEntity::getMaster, true));
-        //标记输注
-        result.markInfusion(deviceHistories);
-        List<ClinicStatsQueryResult> statsQueryResults = deviceHistories.stream().map(history -> {
-            ClinicStatsQueryResult statsQueryResult = new ClinicStatsQueryResult();
-            statsQueryResult.setInputDose(history.getInputDose());
-            statsQueryResult.setInValidCount(history.getPcaInvalidCount());
-            statsQueryResult.setValidCount(history.getPcaValidCount());
-            statsQueryResult.setUploadTime(history.getUploadTime());
-            return statsQueryResult;
-        }).collect(Collectors.toList());
-        //填充统计信息
-        result.setStats(ClinicStatsReturnResult.of(statsQueryResults));
-
-
-
+        if(Boolean.TRUE.equals(clinic.getMonitorType())){
+            //填充输注记录
+            List<BusInfusionHistoryEntity> infusionHistories = infusionHistoryService.list(new QueryWrapper<BusInfusionHistoryEntity>().lambda()
+                    .eq(BusInfusionHistoryEntity::getClinicId, clinicId)
+                    .orderByAsc(BusInfusionHistoryEntity::getStartTime));
+
+            result.fillUndoInfo(infusionHistories);
+
+            //添加设备别名
+            Map<String, List<BusInfusionHistoryEntity>> infusionByDeviceId = infusionHistories.stream().collect(Collectors.groupingBy(BusInfusionHistoryEntity::getDeviceId));
+            infusionByDeviceId.forEach((deviceId,infusions)->{
+                String alias = deviceRegistry.getOperator(deviceId).getAlias();
+                infusions.forEach(infusion->infusion.setAlias(alias));
+            });
+
+            List<String> infusionIds = infusionHistories.stream().map(BusInfusionHistoryEntity::getId).collect(Collectors.toList());
+            List<BusInfusionModifyEntity> infusionModifies = infusionModifyService.list(new QueryWrapper<BusInfusionModifyEntity>().lambda()
+                    .in(BusInfusionModifyEntity::getInfusionId, infusionIds));
+
+            result.fillInfusionRecords(infusionHistories,infusionModifies);
+
+            List<BusDeviceHistoryEntity> deviceHistories = deviceHistoryService.list(new QueryWrapper<BusDeviceHistoryEntity>()
+                    .lambda()
+                    .select(BusDeviceHistoryEntity::getInfusionId,BusDeviceHistoryEntity::getPcaValidCount,BusDeviceHistoryEntity::getInfusionModifyId,
+                            BusDeviceHistoryEntity::getPcaInvalidCount,BusDeviceHistoryEntity::getInputDose,BusDeviceHistoryEntity::getUploadTime)
+                    .in(BusDeviceHistoryEntity::getInfusionId, infusionIds)
+                    .eq(BusDeviceHistoryEntity::getMaster, true));
+            //标记输注
+            result.markInfusion(deviceHistories);
+            List<ClinicStatsQueryResult> statsQueryResults = deviceHistories.stream().map(history -> {
+                ClinicStatsQueryResult statsQueryResult = new ClinicStatsQueryResult();
+                statsQueryResult.setInputDose(history.getInputDose());
+                statsQueryResult.setInValidCount(history.getPcaInvalidCount());
+                statsQueryResult.setValidCount(history.getPcaValidCount());
+                statsQueryResult.setUploadTime(history.getUploadTime());
+                return statsQueryResult;
+            }).collect(Collectors.toList());
+            //填充统计信息
+            result.setStats(ClinicStatsReturnResult.of(statsQueryResults));
+        }
         return R.success(result);
     }
 

+ 2 - 1
coffee-system/src/main/java/com/coffee/bus/controller/BusDeviceController.java

@@ -29,6 +29,7 @@ import lombok.extern.slf4j.Slf4j;
 import org.springframework.web.bind.annotation.*;
 import org.springframework.web.context.request.async.DeferredResult;
 
+import java.io.Serializable;
 import java.util.List;
 import java.util.Objects;
 import java.util.concurrent.CompletableFuture;
@@ -92,7 +93,7 @@ public class BusDeviceController extends BaseCrudController<BusDeviceEntity, Str
     @Override
     @PostMapping("/add")
     @ApiOperation(value = "新增单个数据,并返回新增后的数据.")
-    public R<BusDeviceEntity> add(BusDeviceEntity payload) {
+    public R<BusDeviceEntity> add(@RequestAttribute("tenantId")@ApiParam(hidden = true) Serializable tenantId,@RequestBody BusDeviceEntity payload) {
         log.info("添加设备");
         // 设备id不能为空
         if (StrUtil.isEmpty(payload.getDeviceId())){

+ 8 - 0
coffee-system/src/main/java/com/coffee/bus/controller/BusDeviceManualController.java

@@ -5,6 +5,7 @@ import com.coffee.bus.controller.vo.ClinicEditVo;
 import com.coffee.bus.service.LocalBusDeviceManualService;
 import com.coffee.bus.service.dto.ManualMonitorQuery;
 import com.coffee.bus.service.dto.ManualMonitorResult;
+import com.coffee.bus.service.dto.MonitorTimeStatsCountResult;
 import com.coffee.common.result.R;
 import io.swagger.annotations.Api;
 import io.swagger.annotations.ApiOperation;
@@ -36,4 +37,11 @@ public class BusDeviceManualController {
     public R<List<ManualMonitorResult>> list(@RequestBody ManualMonitorQuery query){
         return R.success(deviceManualService.selectMonitor(query));
     }
+
+    @PostMapping("/stats/time")
+    @SaCheckPermission("device:manual:query")
+    @ApiOperation(value = "按照时间统计病人监控数量",notes = "权限【device:manual:query】")
+    public R<MonitorTimeStatsCountResult> statsTime(){
+        return R.success(deviceManualService.timeStats(null));
+    }
 }

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

@@ -5,6 +5,7 @@ import cn.dev33.satoken.annotation.SaCheckPermission;
 import cn.dev33.satoken.annotation.SaMode;
 import cn.hutool.core.util.ObjectUtil;
 import cn.hutool.core.util.StrUtil;
+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.mapper.Mapper;
@@ -15,6 +16,7 @@ import com.coffee.bus.hospital.HospitalManagerRegister;
 import com.coffee.bus.hospital.his.strategy.HisStrategyEnum;
 import com.coffee.bus.hospital.script.ScriptManager;
 import com.coffee.bus.service.LocalBusHospitalService;
+import com.coffee.bus.service.dto.HospitalScriptResult;
 import com.coffee.common.crud.BaseService;
 import com.coffee.common.crud.controller.BaseCrudController;
 import com.coffee.common.exception.CustomException;
@@ -23,7 +25,6 @@ import io.swagger.annotations.Api;
 import io.swagger.annotations.ApiOperation;
 import io.swagger.annotations.ApiParam;
 import lombok.AllArgsConstructor;
-import org.simpleframework.xml.Attribute;
 import org.springframework.web.bind.annotation.*;
 
 /**
@@ -58,11 +59,11 @@ public class BusHospitalController extends BaseCrudController<BusHospitalEntity,
 
     @PostMapping("/{id}/script")
     @SaCheckPermission("bus:hospital:script:save")
-    @ApiOperation(value = "保存医院信息解析脚本",notes = "保存医院信息解析脚本,权限【bus:hospital:script:save】")
+    @ApiOperation(value = "保存医院信息解析草稿脚本",notes = "保存医院信息解析脚本,权限【bus:hospital:script:save】")
     public R script(@PathVariable("id") String id,@RequestBody Script script){
         BusHospitalEntity busHospitalEntity = new BusHospitalEntity();
         busHospitalEntity.setId(id);
-        busHospitalEntity.setScript(script);
+        busHospitalEntity.setDraftScript(script);
         if (this.getService()
                 .updateById(busHospitalEntity)) {
             scriptManager.resetScript(id,script.getId(),script.getContent());
@@ -83,7 +84,7 @@ public class BusHospitalController extends BaseCrudController<BusHospitalEntity,
     public R draftScript(@RequestAttribute("tenantId")@ApiParam(hidden = true) String tenantId, @RequestBody Script script){
         scriptManager.check(script.getContent(),script.getType());
         hospitalService.update(new UpdateWrapper<BusHospitalEntity>().lambda().eq(BusHospitalEntity::getId,tenantId)
-                .set(BusHospitalEntity::getScript,script));
+                .set(BusHospitalEntity::getDraftScript, JSONUtil.toJsonStr(script)));
         return R.success(true);
     }
 
@@ -96,7 +97,7 @@ public class BusHospitalController extends BaseCrudController<BusHospitalEntity,
             throw new CustomException("草稿脚本内容为空,发布失败");
         }
         hospitalService.update(new UpdateWrapper<BusHospitalEntity>().lambda().eq(BusHospitalEntity::getId,tenantId)
-                .set(BusHospitalEntity::getScript,hospital.getDraftScript()));
+                .set(BusHospitalEntity::getScript,JSONUtil.toJsonStr(hospital.getDraftScript())));
         hospitalManagerRegister.refresh(tenantId,false,false,true);
         return R.success(true);
     }
@@ -112,7 +113,7 @@ public class BusHospitalController extends BaseCrudController<BusHospitalEntity,
         hospitalService.update(new UpdateWrapper<BusHospitalEntity>()
                 .lambda()
                 .eq(BusHospitalEntity::getId,tenantId)
-                .set(BusHospitalEntity::getStrategy,strategy));
+                .set(BusHospitalEntity::getStrategy,strategy.getValue()));
         return R.success(true);
     }
 
@@ -121,15 +122,16 @@ public class BusHospitalController extends BaseCrudController<BusHospitalEntity,
     @SaCheckPermission(mode = SaMode.OR,value = {"bus:hospital:edit","bus:hospital:add"})
     @ApiOperation(value = "校验医院名称是否重复",notes = "权限【bus:hospital:edit 或 bus:hospital:edit】")
     public R<Boolean> validate(@RequestBody String name){
-        return R.success(this.hospitalService.validateName(name));
+        return R.success(this.hospitalService.isExistName(name));
     }
 
 
     @PostMapping("/look/script")
     @SaCheckPermission("bus:hospital:script:query")
     @ApiOperation(value = "查看医院脚本信息",notes = "His对接策略编辑,权限【bus:hospital:script:query】")
-    public R<BusHospitalEntity> lookScript(@RequestAttribute("tenantId") String id){
-        return R.success(this.hospitalService.getOne(new QueryWrapper<BusHospitalEntity>().lambda().select(BusHospitalEntity::getId,BusHospitalEntity::getScript,BusHospitalEntity::getStrategy,BusHospitalEntity::getDraftScript)
+    public R<BusHospitalEntity> lookScript(@RequestAttribute("tenantId")@ApiParam(hidden = true) String id){
+        return R.success(this.hospitalService.getOne(new QueryWrapper<BusHospitalEntity>().lambda()
+                .select(BusHospitalEntity::getId,BusHospitalEntity::getScript,BusHospitalEntity::getStrategy,BusHospitalEntity::getDraftScript)
                 .eq(BusHospitalEntity::getId,id)));
     }
 }

+ 43 - 0
coffee-system/src/main/java/com/coffee/bus/controller/BusInfusionHistoryController.java

@@ -0,0 +1,43 @@
+package com.coffee.bus.controller;
+
+import cn.dev33.satoken.SaManager;
+import cn.dev33.satoken.stp.StpLogic;
+import com.baomidou.mybatisplus.core.mapper.Mapper;
+import com.coffee.bus.entity.BusInfusionHistoryEntity;
+import com.coffee.bus.service.LocalBusInfusionHistoryService;
+import com.coffee.common.crud.BaseService;
+import com.coffee.common.crud.controller.BaseQueryController;
+import io.swagger.annotations.Api;
+import lombok.AllArgsConstructor;
+import org.springframework.web.bind.annotation.RequestMapping;
+import org.springframework.web.bind.annotation.RestController;
+
+/**
+ * @author lifang
+ * @version 1.0.0
+ * @ClassName BusInfusionHistoryController.java
+ * @Description TODO
+ * @createTime 2022年05月27日 15:44:00
+ */
+@RestController
+@AllArgsConstructor
+@RequestMapping("/bus/infusion")
+@Api(tags = "输注历史管理",description = "输注历史管理,查询操作权限【bus:infusion:query】")
+public class BusInfusionHistoryController implements BaseQueryController<BusInfusionHistoryEntity, String> {
+    private final LocalBusInfusionHistoryService infusionHistoryService;
+
+    @Override
+    public BaseService<? extends Mapper<BusInfusionHistoryEntity>, BusInfusionHistoryEntity, String> getService() {
+        return infusionHistoryService;
+    }
+
+    @Override
+    public String getPermissionPrefix() {
+        return "bus:infusion";
+    }
+
+    @Override
+    public StpLogic getStpLogin() {
+        return SaManager.getStpLogic("");
+    }
+}

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

@@ -269,8 +269,14 @@ public class BusPatientController  implements BaseQueryController<BusPatientEnti
         if(haveDevice){
             BusInfusionHistoryEntity infusion =infusionService.currentInClinic(clinic.getId());
             result.setInfusion(infusion);
+            if(StrUtil.isBlank(clinic.getWard())){
+                clinic.setWard(infusion.getWard());
+            }
+            if(StrUtil.isBlank(clinic.getBedNo())){
+                clinic.setBedNo(infusion.getBedNo());
+            }
             if(StrUtil.isNotEmpty(infusion.getClinicId())){
-                result.setClinic(clinicService.getById(infusion.getClinicId()));
+                result.setClinic(clinic);
             }
         }else {
             //无泵查看

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

@@ -104,10 +104,6 @@ public class BusClinicEntity extends TenantGenericEntity<String,String> {
     @ApiModelProperty(value = "临床是否结束,0、未结束 1、结束 ")
     private Boolean finished;
 
-    @ApiModelProperty(value = "临床使用过的设备号")
-    @TableField(typeHandler = FastjsonTypeHandler.class,javaType = true)
-    private Set<String> deviceCodes;
-
     @TableField(fill = FieldFill.INSERT)
     @TableLogic(value = "0",delval = "1")
     private Integer isDelete;

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

@@ -11,6 +11,7 @@ import com.fasterxml.jackson.annotation.JsonIgnoreProperties;
 import io.swagger.annotations.ApiModel;
 import io.swagger.annotations.ApiModelProperty;
 import lombok.Data;
+import org.apache.ibatis.type.JdbcType;
 import org.hibernate.validator.constraints.Length;
 
 import java.util.Date;
@@ -73,11 +74,11 @@ public class BusHospitalEntity implements RecordModifierEntity, RecordCreationEn
     private GeoPoint coordinate;
 
     @ApiModelProperty("发布的脚本内容")
-    @TableField(typeHandler = FastjsonTypeHandler.class)
+    @TableField(typeHandler = FastjsonTypeHandler.class,updateStrategy = FieldStrategy.NEVER)
     private Script script;
 
     @ApiModelProperty("草稿(编辑中的脚本内容)")
-    @TableField(typeHandler = FastjsonTypeHandler.class)
+    @TableField(typeHandler = FastjsonTypeHandler.class,updateStrategy = FieldStrategy.NEVER)
     private Script draftScript;
 
     @ApiModelProperty("医院唯一编码,自动生成")

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

@@ -1,5 +1,6 @@
 package com.coffee.bus.hospital;
 
+import cn.hutool.core.util.StrUtil;
 import cn.hutool.json.JSONUtil;
 import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
 import com.coffee.bus.bean.Script;
@@ -168,8 +169,8 @@ public class HospitalManager {
 
     public void refreshScript(){
         BusHospitalEntity hospital = hospitalService.getById(hospitalId);
-        ScriptParse scriptParse = scriptManager.getById(hospitalId);
-        scriptManager.resetScript(hospitalId,scriptParse.getId(), Optional.ofNullable(hospital.getScript()).orElse(new Script()).getContent());
+        Script script=Optional.ofNullable(hospital.getScript()).orElse(new Script());
+        scriptManager.resetScript(hospitalId,StrUtil.isNotEmpty(script.getContent())?"python":"default",script.getContent());
     }
 
 }

+ 6 - 51
coffee-system/src/main/java/com/coffee/bus/hospital/his/HisScriptSession.java

@@ -150,6 +150,10 @@ public class HisScriptSession {
      * @return BusClinicEntity
      */
     public  DeferredResult<R<BusClinicEntity>>  asyncGetPatientInfo(String patientCode,long timeout, TimeUnit unit,boolean needResult){
+        if(!isOnline()){
+            //将请求缓存 todo
+            throw new CustomException("医院不在线,拉取信息失败");
+        }
         String messageId = IdWorker.getIdStr();
         DeferredResult<R<BusClinicEntity>> result = new DeferredResult<>(unit.toMillis(timeout));
         HisRequest request = HisRequest.builder()
@@ -187,7 +191,7 @@ public class HisScriptSession {
      * @return BusClinicEntity 开始时间最大的手术信息
      */
     public BusClinicEntity handle(String text,String patientCode){
-        ScriptParse script = scriptManager.getById(hospitalId);
+        ScriptParse script = scriptManager.lookUpHospital(hospitalId);
         if(script==null){
             log.warn("没有获取到医院{}的解析脚本信息,不处理该条数据",hospitalId);
             script=new DefaultParse();
@@ -217,6 +221,7 @@ 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);
@@ -263,56 +268,6 @@ public class HisScriptSession {
     private void sendRequest(ChannelContext channelContext,HisRequest request){
         hisRequestMap.put(request.getMessageId(),request);
         Tio.send(channelContext, WsResponse.fromText(JSONUtil.toJsonStr(request),"utf-8"));
-        executorService.schedule(()->{
-            BusClinicEntity clinicEntity = clinicService.recentClinicByPatientCode("1", request.getPatientCode());
-            if(clinicEntity==null){
-                clinicEntity=new BusClinicEntity();
-            }
-            List<BusClinicEntity> clinic = new ArrayList<>();
-            HisResponse hisResponse = new HisResponse();
-            hisResponse.setMessageId(request.getMessageId());
-            hisResponse.setSuccess(true);
-            hisResponse.setTimestamp(new Date());
-            hisResponse.setPatientCode(request.getPatientCode());
-            for (int i = 0; i < 6; i++) {
-                clinicEntity.setId(null);
-                clinicEntity.setMonitorType(true);
-                clinicEntity.setPatientCode(request.getPatientCode());
-                clinicEntity.setPatientGender(SexEnum.MAN);
-                clinicEntity.setPatientAge(RandomUtil.randomInt(20,40));
-                clinicEntity.setPatientName("病人名称"+i);
-                clinicEntity.setSurgeryName("新的临床数据"+i);
-                clinicEntity.setSurgeryDoctor("手术医生"+i);
-                clinicEntity.setAnaDoctor("麻醉医生"+i);
-                clinicEntity.setConfigPerson("配置人员"+i);
-                clinicEntity.setAnaType("麻醉方式"+i);
-                clinicEntity.setStartTime(DateUtil.yesterday());
-                clinicEntity.setAnalType("镇痛方式"+i);
-                clinicEntity.setEntrust("医嘱"+i);
-                clinicEntity.setAsa("ASA"+i);
-                clinicEntity.setTenantId(this.getHospitalId());
-                FormulaDrugDomain formulaDrugDomain = new FormulaDrugDomain();
-                formulaDrugDomain.setName("镇痛配方"+i);
-
-                FormulaDrugDetailDomain detailDomain = new FormulaDrugDetailDomain();
-                detailDomain.setDose("1");
-                detailDomain.setUnit("ml");
-                detailDomain.setName("鸦胆子");
-                FormulaDrugDetailDomain detailDomain1 = new FormulaDrugDetailDomain();
-                detailDomain1.setDose("1");
-                detailDomain1.setUnit("ml");
-                detailDomain1.setName("利多卡因");
-                formulaDrugDomain.setDetail(Arrays.asList(detailDomain,detailDomain1));
-
-                clinicEntity.setFormula(formulaDrugDomain);
-                BusClinicEntity c = new BusClinicEntity();
-                BeanUtil.copyProperties(clinicEntity,c);
-                c.setStartTime(RandomUtil.randomDate(new Date(), DateField.HOUR_OF_DAY,-100,0));
-                clinic.add(c);
-            }
-            hisResponse.setContext(JSONUtil.toJsonStr(clinic));
-            response(hisResponse);
-        },1,TimeUnit.SECONDS);
     }
 
     public void response(HisResponse hisResponse){

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

@@ -1,6 +1,7 @@
 package com.coffee.bus.hospital.his.strategy;
 
 import com.baomidou.mybatisplus.annotation.IEnum;
+import com.fasterxml.jackson.annotation.JsonFormat;
 import lombok.AllArgsConstructor;
 import lombok.Getter;
 
@@ -13,6 +14,7 @@ import lombok.Getter;
  */
 @AllArgsConstructor
 @Getter
+@JsonFormat(shape = JsonFormat.Shape.OBJECT)
 public enum  HisStrategyEnum  implements IEnum<Integer> {
     NONE(0,"无his对接"),
     ALL(1,"拉取所有的病人数据"),

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

@@ -57,6 +57,7 @@ public class EqualsStrategyHandler implements HisAllStrategyHandler {
         for (int i = 0; i < source.size(); i++) {
             clinicService.compareFromHis(source.get(i),target.get(i));
         }
+        clinicService.setCurrentClinicByHis(CollectionUtil.getFirst(source.iterator()));
     }
 
     @Override

+ 0 - 32
coffee-system/src/main/java/com/coffee/bus/hospital/script/PythonParse.java

@@ -89,36 +89,4 @@ public class PythonParse implements ScriptParse {
         return executeResult;
 
     }
-
-    public static void main(String[] args){
-        Properties p = new Properties();
-        p.setProperty("python.console.encoding", "UTF-8");
-        PySystemState systemState = Py.getSystemState();
-        PyString xml = new PyString("\\python-modules");
-        systemState.modules.__add__(xml);
-        PythonInterpreter.initialize(System.getProperties(), p, new String[] {});
-        PythonInterpreter pythonInterpreter = new PythonInterpreter();
-        String str = "# -*- coding: utf-8 -*-\n" +
-                "import sys\n" +
-                "reload(sys)\n" +
-                "sys.setdefaultencoding('utf-8')\n" +
-                "import json\n" +
-                "import xmltodict as xmltodict\n" +
-                "\n" +
-                "\n" +
-                "def parse(str):\n" +
-                "\n" +
-                "    json_result={}\n" +
-                "    json_obj=  json.loads(str)\n" +
-                "\n" +
-                "    json_result['1']=json_obj['name']\n" +
-                "    return json_result";
-        pythonInterpreter.exec(Py.newStringUTF8(str));
-        PyFunction parse = pythonInterpreter.get("parse", PyFunction.class);
-        PyObject pyObject = parse.__call__(Py.newStringUTF8( "{\"name\": \"小明\", \"age\": \"12\"}"));
-        JSON parse1 = JSONUtil.parse(pyObject);
-        pythonInterpreter.close();
-        System.out.println(pyObject);
-        System.out.println(parse1);
-    }
 }

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

@@ -1,5 +1,6 @@
 package com.coffee.bus.service;
 
+import cn.hutool.core.date.LocalDateTimeUtil;
 import cn.hutool.core.util.StrUtil;
 import cn.hutool.json.JSONUtil;
 import com.alibaba.fastjson.JSON;
@@ -11,8 +12,7 @@ import com.coffee.bus.controller.vo.MonitorFinishedVo;
 import com.coffee.bus.entity.BusClinicEntity;
 import com.coffee.bus.entity.BusDeviceManualEntity;
 import com.coffee.bus.mapper.BusDeviceManualMapper;
-import com.coffee.bus.service.dto.ManualMonitorQuery;
-import com.coffee.bus.service.dto.ManualMonitorResult;
+import com.coffee.bus.service.dto.*;
 import com.coffee.common.crud.BaseService;
 import com.coffee.common.exception.CustomException;
 import lombok.extern.slf4j.Slf4j;
@@ -20,6 +20,9 @@ import org.springframework.beans.factory.annotation.Autowired;
 import org.springframework.context.annotation.Lazy;
 import org.springframework.stereotype.Service;
 import org.springframework.transaction.annotation.Transactional;
+
+import java.time.LocalDateTime;
+import java.time.ZoneOffset;
 import java.util.*;
 /**
  * @author lifang
@@ -111,4 +114,55 @@ public class LocalBusDeviceManualService extends BaseService<BusDeviceManualMapp
                 .set(BusClinicEntity::getEndTime,vo.getUndo().getUndoTime())
                 .set(BusClinicEntity::getUndoConfig, vo.getUndo(),"typeHandler = com.baomidou.mybatisplus.extension.handlers.FastjsonTypeHandler"));
     }
+
+    public MonitorTimeStatsCountResult timeStats(String tenantId) {
+        ManualMonitorQuery query = new ManualMonitorQuery();
+
+        List<ManualMonitorResult> manualMonitorResults = this.selectMonitor(query);
+        MonitorTimeStatsCountResult result = new MonitorTimeStatsCountResult();
+        manualMonitorResults.forEach(monitor->{
+            Date startTime = monitor.getMonitorStartTime();
+            if(startTime==null){
+                return;
+            }
+            if (includeTimes(startTime, 0)) {
+                result.setToday(result.getToday()+1);
+                return;
+            }
+            if (includeTimes(startTime, -1)) {
+                result.setOneDay(result.getOneDay()+1);
+                return;
+            }
+            if (includeTimes(startTime, -2)) {
+                result.setTwoDay(result.getTwoDay()+1);
+                return;
+            }
+            if (includeTimes(startTime, -3)) {
+                result.setThreeDay(result.getThreeDay()+1);
+                return;
+            }
+            result.setBeyondThreeDay(result.getBeyondThreeDay()+1);
+        });
+
+        return result;
+    }
+
+    /**
+     * 描述: 判断所给时间是否在存在于某一时间段内
+     * @author lifang
+     * @date 2022/5/8 22:47
+     * @param time 时间
+     * @param offset 时间偏移量,单位:天 以当天时间为基准进行偏移
+     * @return boolean
+     */
+    private boolean includeTimes(Date time,int offset){
+        if(time==null){
+            return false;
+        }
+        LocalDateTime dateTime = LocalDateTime.now().plusDays(offset);
+        LocalDateTime beginTime = LocalDateTimeUtil.beginOfDay(dateTime);
+        LocalDateTime endTime = LocalDateTimeUtil.endOfDay(dateTime);
+        return beginTime.toInstant(ZoneOffset.of("+8")).toEpochMilli()<time.getTime()
+                && time.getTime()<endTime.toInstant(ZoneOffset.of("+8")).toEpochMilli();
+    }
 }

+ 17 - 6
coffee-system/src/main/java/com/coffee/bus/service/LocalBusHospitalService.java

@@ -13,6 +13,7 @@ import com.coffee.bus.utils.CodeUtils;
 import com.coffee.common.cache.ConfigStorage;
 import com.coffee.common.cache.manager.ConfigStorageManager;
 import com.coffee.common.config.mybatis.GetNameInterface;
+import com.coffee.common.config.websocket.HospitalCodeCheck;
 import com.coffee.common.crud.BaseService;
 import com.coffee.common.exception.CustomException;
 import org.springframework.beans.factory.annotation.Autowired;
@@ -22,7 +23,7 @@ import org.springframework.stereotype.Service;
 
 import javax.annotation.PostConstruct;
 import java.util.List;
-import java.util.Map;
+import java.util.Optional;
 
 /**
  * @author lifang
@@ -32,7 +33,7 @@ import java.util.Map;
  * @createTime 2022年03月19日 09:27:00
  */
 @Service
-public class LocalBusHospitalService extends BaseService<BusHospitalMapper, BusHospitalEntity,String> implements CommandLineRunner, GetNameInterface<String,String> {
+public class LocalBusHospitalService extends BaseService<BusHospitalMapper, BusHospitalEntity,String> implements CommandLineRunner, GetNameInterface<String,String>, HospitalCodeCheck {
     @Autowired
     @Lazy
     private ConfigStorageManager configStorageManager;
@@ -54,7 +55,7 @@ public class LocalBusHospitalService extends BaseService<BusHospitalMapper, BusH
     public void validateBeforeSave(BusHospitalEntity entity) {
         long id = IdWorker.getId();
         String name = entity.getName();
-        if(validateName(name)){
+        if(isExistName(name)){
             throw new CustomException(String.format("医院名称[%s]不可重复",entity.getName()));
         }
         if(entity.getStrategy()==null){
@@ -75,7 +76,7 @@ public class LocalBusHospitalService extends BaseService<BusHospitalMapper, BusH
             return;
         }
         if (!ObjectUtil.equal(entity.getName(), hospital.getName())) {
-            if(validateName(entity.getName())){
+            if(!isExistName(entity.getName())){
                 throw new CustomException(String.format("医院名称[%s]不可重复",entity.getName()));
             }
         }
@@ -149,7 +150,17 @@ public class LocalBusHospitalService extends BaseService<BusHospitalMapper, BusH
      * @param name
      * @return boolean
      */
-    public boolean validateName(String name){
-        return this.getOne(new QueryWrapper<BusHospitalEntity>().lambda().eq(BusHospitalEntity::getName,name).last("limit 1"))==null;
+    public boolean isExistName(String name){
+        return this.count(new QueryWrapper<BusHospitalEntity>().lambda().eq(BusHospitalEntity::getName,name))!=0;
+    }
+
+    @Override
+    public boolean isExistCode(String code) {
+        return this.count(new QueryWrapper<BusHospitalEntity>().lambda().eq(BusHospitalEntity::getCode,code))!=0;
+    }
+
+    @Override
+    public String getHospitalId(String code) {
+        return Optional.ofNullable(this.getOne(new QueryWrapper<BusHospitalEntity>().lambda().eq(BusHospitalEntity::getCode,code))).orElse(new BusHospitalEntity()).getId();
     }
 }

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

@@ -273,7 +273,7 @@ public class LocalBusPatientService extends BaseService<BusPatientMapper, BusPat
                     result.setRunningCount(result.getRunningCount()+1);
                 }
                 if(monitor.getDeviceRunState()!=null&&(DeviceStatusEnum.Shutdown.equals(monitor.getDeviceRunState())||DeviceStatusEnum.NoSignal.equals(monitor.getDeviceRunState()))){
-                    result.setWaitingFinish(result.getAlarmCount()+1);
+                    result.setWaitingFinish(result.getWaitingFinish()+1);
                 }
                 //报警数量
                 if(monitor.getDeviceAlarm()!=null&&!monitor.getDeviceAlarm().equals(DeviceAlarmEnum.None)){

+ 54 - 2
coffee-system/src/main/java/com/coffee/bus/service/constant/LocalBusConMixService.java

@@ -1,11 +1,24 @@
 package com.coffee.bus.service.constant;
 
+import cn.hutool.core.util.StrUtil;
+import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
 import com.coffee.bus.entity.BusConMixEntity;
 import com.coffee.bus.enums.ConstantEnum;
+import com.coffee.bus.enums.ConstantMixEnum;
 import com.coffee.bus.mapper.BusConMixMapper;
 import com.coffee.common.crud.BaseService;
+import com.coffee.common.exception.CustomException;
+import com.coffee.common.util.RedissonUtil;
+import org.redisson.api.RMap;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.boot.CommandLineRunner;
 import org.springframework.stereotype.Service;
 
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+import java.util.stream.Collectors;
+
 /**
  * @author lifang
  * @version 1.0.0
@@ -14,10 +27,16 @@ import org.springframework.stereotype.Service;
  * @createTime 2022年03月19日 09:27:00
  */
 @Service
-public class LocalBusConMixService extends AbstractConstantService<BusConMixMapper, BusConMixEntity,String> {
+public class LocalBusConMixService extends AbstractConstantService<BusConMixMapper, BusConMixEntity,String> implements CommandLineRunner {
+    private Map<String, RMap<String,String>> wardMap=new HashMap<>();
+    @Autowired
+    private RedissonUtil redissonUtil;
+
     @Override
     public void validateBeforeSave(BusConMixEntity entity) {
-
+        if (ConstantMixEnum.ward.equals(entity.getType())&& StrUtil.isNotEmpty(entity.getCode())) {
+            throw new CustomException("病区编号不能为空");
+        }
     }
 
     @Override
@@ -30,8 +49,41 @@ public class LocalBusConMixService extends AbstractConstantService<BusConMixMapp
 
     }
 
+    @Override
+    public void postSave(BusConMixEntity entity) {
+        if (ConstantMixEnum.ward.equals(entity.getType())&& StrUtil.isNotEmpty(entity.getCode())) {
+            wardMap.get(entity.getTenantId()).putAsync(entity.getCode(),entity.getName());
+        }
+    }
+
+    @Override
+    public void postUpdate(BusConMixEntity entity) {
+        if (ConstantMixEnum.ward.equals(entity.getType())&& StrUtil.isNotEmpty(entity.getCode())) {
+            wardMap.computeIfAbsent(entity.getTenantId(), k -> redissonUtil.getRedissonClient().getMapCache(k))
+                    .putAsync(entity.getCode(),entity.getName());
+        }
+    }
+
+    public String getWard(String tenantId,String code){
+        if(StrUtil.isBlank(tenantId)){
+            return code;
+        }
+        return wardMap.get(tenantId).getOrDefault(code,code);
+    }
+
     @Override
     public ConstantEnum getName() {
         return ConstantEnum.mix;
     }
+
+    @Override
+    public void run(String... args) {
+        List<BusConMixEntity> conList = list(new QueryWrapper<BusConMixEntity>().lambda().eq(BusConMixEntity::getType, ConstantMixEnum.ward));
+        Map<String, List<BusConMixEntity>> conByHospital = conList.stream().collect(Collectors.groupingBy(BusConMixEntity::getTenantId));
+        conByHospital.forEach((tenantId,cons)->{
+            RMap<String, String> rmap = wardMap.computeIfAbsent(tenantId, k -> redissonUtil.getRedissonClient().getMap(tenantId));
+            cons.stream().filter(con->StrUtil.isNotBlank(con.getCode())).forEach(con->rmap.putAsync(con.getCode(),con.getName()));
+        });
+
+    }
 }

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

@@ -32,7 +32,7 @@ public class ClinicQuery implements Serializable {
     private String patientCode;
 
     @ApiModelProperty("病区")
-    private String ward;
+    private List<String> ward;
 
     @ApiModelProperty("床号")
     private String bedNo;

+ 34 - 0
coffee-system/src/main/java/com/coffee/bus/service/dto/HospitalScriptResult.java

@@ -0,0 +1,34 @@
+package com.coffee.bus.service.dto;
+
+import com.baomidou.mybatisplus.annotation.FieldStrategy;
+import com.baomidou.mybatisplus.annotation.TableField;
+import com.coffee.bus.bean.Script;
+import com.coffee.bus.hospital.his.strategy.HisStrategyEnum;
+import io.swagger.annotations.ApiModelProperty;
+import lombok.AllArgsConstructor;
+import lombok.Data;
+import lombok.NoArgsConstructor;
+
+/**
+ * @author lifang
+ * @version 1.0.0
+ * @ClassName HospitalScriptResult.java
+ * @Description TODO
+ * @createTime 2022年05月26日 15:52:00
+ */
+@Data
+@AllArgsConstructor(staticName = "of")
+@NoArgsConstructor
+public class HospitalScriptResult {
+
+    private String id;
+
+    @ApiModelProperty("发布的脚本内容")
+    private Script script;
+
+    @ApiModelProperty("接收his数据的策略, 1(默认)、获取病人全部信息 2、获取病人部分信息 3、获取病人最新信息")
+    private HisStrategyEnum strategy;
+
+    @ApiModelProperty("草稿(编辑中的脚本内容)")
+    private Script draftScript;
+}

+ 4 - 0
coffee-system/src/main/java/com/coffee/bus/service/dto/PatientMonitorResult.java

@@ -36,6 +36,10 @@ public class PatientMonitorResult implements Serializable {
     @ApiModelProperty(value = "性别")
     private SexEnum gender;
 
+    private String classification;
+
+    private Integer dataNum;
+
     @ApiModelProperty(value = "病人报警信息",example = "泵重复,无泵")
     private PatientAlarmEnum patientAlarm;
 

+ 6 - 2
coffee-system/src/main/java/com/coffee/bus/web/handler/CheckTimeHandler.java

@@ -5,6 +5,7 @@ import cn.hutool.core.util.StrUtil;
 import cn.hutool.crypto.digest.DigestUtil;
 import cn.hutool.json.JSONObject;
 import cn.hutool.json.JSONUtil;
+import com.coffee.common.cache.value.Value;
 import com.coffee.common.redis.RedisUtils;
 import com.coffee.common.result.R;
 import com.coffee.common.result.ResultCode;
@@ -29,12 +30,15 @@ import java.nio.charset.Charset;
 public class CheckTimeHandler implements HandlerInterceptor {
     RedisUtils redisUtils;
     @Override
-    public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler){
+    public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws IOException {
         String method = request.getMethod();
+        Long timestamp = Value.simple(request.getHeader("Timestamp")).asLong();
+        if(timestamp==null){
+            response.getOutputStream().write(JSONUtil.parse(R.result(ResultCode.PARAM_MISS,"请检查是否携带Timestamp、Sign、Authorization")).toString().getBytes());
+        }
         if (method.equals("POST")) {
             //post 请求验证参数
             String sign = request.getHeader("Sign");
-            String timestamp = request.getHeader("Timestamp");
 //            redisUtils.get()
         }
         //get请求

+ 184 - 0
coffee-system/src/main/java/com/coffee/bus/websocket/DefaultWebSocketMsgHandler.java

@@ -0,0 +1,184 @@
+package com.coffee.bus.websocket;
+
+import cn.dev33.satoken.stp.StpUtil;
+import cn.hutool.core.collection.CollectionUtil;
+import cn.hutool.core.util.ObjectUtil;
+import cn.hutool.core.util.StrUtil;
+import cn.hutool.json.JSONUtil;
+import com.coffee.bus.hospital.his.HisResponse;
+import com.coffee.bus.hospital.his.HisScriptSession;
+import com.coffee.bus.hospital.his.HisScriptSessionManager;
+import com.coffee.common.Constants;
+import com.coffee.common.bo.LoginUser;
+import com.coffee.common.config.websocket.HospitalCodeCheck;
+import com.coffee.common.config.websocket.MessagingRequest;
+import com.coffee.common.config.websocket.handler.WsHandler;
+import com.coffee.common.result.R;
+import lombok.AllArgsConstructor;
+import lombok.extern.slf4j.Slf4j;
+import org.springframework.boot.autoconfigure.AutoConfigureAfter;
+import org.springframework.data.redis.core.RedisTemplate;
+import org.springframework.stereotype.Component;
+import org.tio.core.ChannelContext;
+import org.tio.core.Tio;
+import org.tio.http.common.HttpRequest;
+import org.tio.http.common.HttpResponse;
+import org.tio.websocket.common.WsRequest;
+import org.tio.websocket.common.WsResponse;
+import org.tio.websocket.server.handler.IWsMsgHandler;
+import java.util.*;
+import java.util.concurrent.CompletableFuture;
+import java.util.stream.Collectors;
+
+@Component
+@Slf4j
+@AllArgsConstructor
+@AutoConfigureAfter(RedisTemplate.class)
+public class DefaultWebSocketMsgHandler implements IWsMsgHandler {
+    private final List<WsHandler> messageHandlers;
+    private final HisScriptSessionManager scriptSessionManager;
+    private final HospitalCodeCheck codeCheck;
+    @Override
+    public HttpResponse handshake(HttpRequest httpRequest, HttpResponse httpResponse, ChannelContext channelContext) {
+        return httpResponse;
+    }
+
+    @Override
+    public void onAfterHandshaked(HttpRequest httpRequest, HttpResponse httpResponse, ChannelContext channelContext) throws Exception {
+        //用户授权码
+        String authorization = httpRequest.getParam("Authorization");
+        if(log.isDebugEnabled()){
+            log.debug("websocket 握手成功,开始进行权限校验,Authorization:{}",authorization);
+        }
+        if(StrUtil.isNullOrUndefined(authorization)){
+            Tio.send(channelContext,WsResponse.fromText(JSONUtil.toJsonStr(R.fail("授权失败")),"utf-8"));
+            //给返回信息一些时间 todo1
+            channelContext.setClosed(true);
+            return;
+        }
+        if (StrUtil.isNotEmpty(authorization)) {
+            Object result = StpUtil.getTokenSessionByToken(authorization).get(Constants.LOGIN_USER_KEY);
+            if(null==result){
+                //尝试医院请求登录
+                String hospitalId = codeCheck.getHospitalId(authorization);
+                if (StrUtil.isNotBlank(hospitalId)) {
+                    channelContext.set(Constants.HOSPITAL_ID,hospitalId);
+                    HisScriptSession hisScriptSession = scriptSessionManager.get(hospitalId);
+                    //绑定
+                    hisScriptSession.bindChannel(channelContext);
+                }else {
+                    unbind(channelContext);
+                    Thread.sleep(50);
+                    channelContext.setClosed(true);
+                    if(log.isDebugEnabled()){
+                        log.debug("Authorization:{},鉴权失败",authorization);
+                    }
+                    Tio.send(channelContext,WsResponse.fromText(JSONUtil.toJsonStr(R.fail("授权失败")),"utf-8"));
+                }
+                return;
+            }else {
+                Tio.bindToken(channelContext, JSONUtil.toJsonStr(authorization));
+                LoginUser loginUser = (LoginUser)result;
+                channelContext.set(Constants.LOGIN_USER_KEY,loginUser);
+            }
+            Tio.send(channelContext,WsResponse.fromText(JSONUtil.toJsonStr(R.success("连接成功")),"utf-8"));
+        }
+    }
+
+    @Override
+    public Object onBytes(WsRequest wsRequest, byte[] bytes, ChannelContext channelContext){
+        return null;
+    }
+
+    @Override
+    public Object onClose(WsRequest wsRequest, byte[] bytes, ChannelContext channelContext) {
+        messageHandlers.forEach(wsHandler -> wsHandler.close(channelContext));
+        return null;
+    }
+
+    @Override
+    public Object onText(WsRequest wsRequest, String message, ChannelContext channelContext) {
+        if (StrUtil.isEmpty(message)) {
+            unbind(channelContext);
+            channelContext.setClosed(true);
+            return null;
+        }
+        //心跳请求 todo
+        if("ping".equals(message.trim().toLowerCase())){
+            Tio.send(channelContext,WsResponse.fromText("pong","utf-8"));
+            return null;
+        }
+        try {
+            synchronized (channelContext){
+                if(log.isDebugEnabled()){
+                    log.debug("websocket 接收到消息,message:{},token:{},userId:{}",message,channelContext.getToken(),JSONUtil.toJsonStr(channelContext.get(Constants.LOGIN_USER_KEY)));
+                }
+                Object user = channelContext.get(Constants.LOGIN_USER_KEY);
+                if(ObjectUtil.isNotNull(user)){
+                    handleUserMessage(wsRequest,message,channelContext);
+                }else {
+                    handleHospitalMessage(wsRequest,message,channelContext,String.valueOf(channelContext.get(Constants.HOSPITAL_ID)));
+                }
+            }
+        }catch (Exception e){
+            log.warn("websocket 接收到异常请求,token:{},message:{},userId:{}",channelContext.getToken(),message,JSONUtil.toJsonStr(channelContext.get(Constants.LOGIN_USER_KEY)));
+            unbind(channelContext);
+            channelContext.setClosed(true);
+        }
+
+        return null;
+    }
+
+    private void unbind(ChannelContext channelContext){
+        Tio.unbindToken(channelContext);
+        Tio.unbindUser(channelContext);
+    }
+
+
+    /**
+     * 描述: 处理用户请求
+     * @author lifang
+     * @date 2022/5/27 9:54
+     * @param wsRequest
+     * @param message
+     * @param channelContext
+     * @return void
+     */
+    private void handleUserMessage(WsRequest wsRequest, String message, ChannelContext channelContext){
+        MessagingRequest messagingRequest = JSONUtil.toBean(message, MessagingRequest.class);
+        messagingRequest.validate();
+        List<WsHandler> collect = messageHandlers
+                .parallelStream()
+                .filter(handler -> messagingRequest.getId().equals(handler.getId()))
+                .collect(Collectors.toList());
+        //传入格式错误,不支持该订阅id
+        if(CollectionUtil.isEmpty(collect)){
+            unbind(channelContext);
+            channelContext.setClosed(true);
+            return;
+        }
+        collect.forEach(handler->handler.onMessage(messagingRequest,channelContext));
+    }
+
+    /**
+     * 描述: 处理医院响应请求
+     * @author lifang
+     * @date 2022/5/27 9:54
+     * @param wsRequest
+     * @param message
+     * @param channelContext
+     * @return void
+     */
+    private void handleHospitalMessage(WsRequest wsRequest, String message, ChannelContext channelContext,String hospitalId){
+        MessagingRequest messagingRequest = JSONUtil.toBean(message, MessagingRequest.class);
+        try {
+            //医院主题请求
+            messagingRequest.validate();
+        }catch (Exception e){
+            //医院响应
+            HisResponse hisResponse = JSONUtil.toBean(message, HisResponse.class);
+            CompletableFuture
+                    .runAsync(()-> scriptSessionManager.get(hospitalId).response(hisResponse));
+        }
+    }
+}

+ 3 - 5
coffee-system/src/main/java/com/coffee/bus/websocket/HisConnectionHandler.java

@@ -8,11 +8,13 @@ import com.coffee.bus.entity.BusHospitalEntity;
 import com.coffee.bus.hospital.his.HisScriptSession;
 import com.coffee.bus.hospital.his.HisScriptSessionManager;
 import com.coffee.bus.service.LocalBusHospitalService;
+import com.coffee.common.config.websocket.DefaultMessageListener;
 import com.coffee.common.config.websocket.MessagingRequest;
 import com.coffee.common.config.websocket.WebSocketConstant;
 import com.coffee.common.config.websocket.handler.Subscribe;
 import com.coffee.common.result.R;
 import lombok.AllArgsConstructor;
+import org.redisson.api.RPatternTopic;
 import org.springframework.stereotype.Component;
 import org.tio.core.ChannelContext;
 import org.tio.core.Tio;
@@ -72,11 +74,7 @@ public class HisConnectionHandler extends Subscribe {
 
     @Override
     public void close(ChannelContext channelContext) {
-        String tenantId=String.valueOf(channelContext.get("tenantId"));
-        if(StrUtil.isEmpty(tenantId)){
-            HisScriptSession hisScriptSession = scriptSessionManager.get(tenantId);
-            hisScriptSession.offline();
-        }
+
     }
 
     @Override

+ 12 - 1
coffee-system/src/main/java/com/coffee/bus/websocket/WebSocketCloseHandler.java

@@ -1,5 +1,10 @@
 package com.coffee.bus.websocket;
 
+import cn.hutool.core.util.ObjectUtil;
+import cn.hutool.core.util.StrUtil;
+import com.coffee.bus.hospital.his.HisScriptSession;
+import com.coffee.bus.hospital.his.HisScriptSessionManager;
+import com.coffee.common.Constants;
 import com.coffee.common.config.websocket.DefaultMessageListener;
 import com.coffee.common.config.websocket.handler.Subscribe;
 import org.springframework.stereotype.Component;
@@ -16,6 +21,7 @@ import java.util.Map;
  */
 @Component
 public class WebSocketCloseHandler extends Subscribe {
+    private HisScriptSessionManager scriptSessionManager;
     @Override
     public String getId() {
         return "";
@@ -23,9 +29,14 @@ public class WebSocketCloseHandler extends Subscribe {
 
     @Override
     public void close(ChannelContext channelContext) {
-        //关闭则取消订阅
+        Object hospitalId=channelContext.get(Constants.HOSPITAL_ID);
+        if (ObjectUtil.isNotNull(hospitalId)) {
+            scriptSessionManager.get(String.valueOf(hospitalId)).offline();;
+        }else {
+            //关闭则取消订阅
 //        Map<String, DefaultMessageListener> topicListeners = getTopicListeners(channelContext);
 //        topicListeners.forEach((topic,listener)->this.unsubscribe(channelContext,topic));
+        }
     }
 
     @Override

+ 5 - 0
coffee-system/src/main/java/com/coffee/bus/websocket/listener/DeviceInfoListener.java

@@ -30,6 +30,7 @@ import org.springframework.stereotype.Component;
 import org.springframework.transaction.annotation.Transactional;
 import java.util.*;
 import java.util.List;
+import java.util.concurrent.TimeUnit;
 import java.util.function.Supplier;
 
 /**
@@ -192,6 +193,10 @@ public class DeviceInfoListener {
             deviceOperator.setStartTime(device.getStartTime());
             deviceOperator.setMaster(device.getMaster());
             deviceOperator.setPatientCode(device.getPatientCode());
+            //新输注异步更新
+            hospitalManagerRegister.get(device.getTenantId())
+                    .getScriptSession()
+                    .asyncGetPatientInfo(device.getPatientCode(),10, TimeUnit.SECONDS,false);
             return null;
         });
         return first;

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

@@ -1,6 +1,7 @@
 package com.coffee.system.entity;
 
 import com.baomidou.mybatisplus.annotation.FieldFill;
+import com.baomidou.mybatisplus.annotation.FieldStrategy;
 import com.baomidou.mybatisplus.annotation.TableField;
 import com.fasterxml.jackson.annotation.JsonFormat;
 import com.fasterxml.jackson.databind.annotation.JsonSerialize;
@@ -67,6 +68,7 @@ public class SysMenu implements Serializable {
     /**
      * 图标
      */
+    @TableField(updateStrategy = FieldStrategy.IGNORED)
     private String icon;
 
     /**

+ 1 - 1
coffee-system/src/main/resources/mapper/bus/BusDeviceHistoryMapper.xml

@@ -8,7 +8,7 @@
          bus_device_history  as h
         join (select * from bus_infusion_history where clinic_id=#{query.clinicId} and device_id=#{query.deviceId}) as i
         on h.infusion_id=i.id
-        order by h.upload_time
+        order by h.upload_time desc
     </select>
 
 

+ 10 - 5
coffee-system/src/main/resources/mapper/bus/BusPatientMapper.xml

@@ -27,11 +27,14 @@
             <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="ward" property="ward" typeHandler="com.coffee.bus.config.mybaits.WardHandler"/>
             <result column="bed_no" property="bedNo"/>
             <result column="total_dose" property="totalDose"/>
             <result column="first_dose" property="firstDose"/>
@@ -91,7 +94,7 @@
             <result column="anal_type" property="analType"/>
             <result column="surgery_doctor" property="surgeryDoctor"/>
             <result column="asa" property="asa"/>
-            <result column="formula" property="formula"/>
+            <result column="formula" property="formula" typeHandler="com.baomidou.mybatisplus.extension.handlers.FastjsonTypeHandler"/>
             <result column="finished" property="finished"/>
             <result column="config_person" property="configPerson"/>
         </resultMap>
@@ -152,6 +155,8 @@
             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.ward as ward,
             i.bed_no as bed_no,
             i.total_dose as total_dose,
@@ -218,9 +223,6 @@
                         #{ward, jdbcType=VARCHAR}
                     </foreach>
                 </if>
-                <if test="query.infusionFinished == true">
-                    and finished=#{query.infusionFinished}
-                </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=")">
@@ -242,6 +244,9 @@
                                 #{alarm, jdbcType=VARCHAR}
                             </foreach>
                         </if>
+                        <if test="query.infusionFinished == true">
+                            or finished=#{query.infusionFinished}
+                        </if>
                         )
                     </when>
                     <otherwise>