浏览代码

add
不良评价

lifang 1 月之前
父节点
当前提交
0575103b9f

+ 1 - 0
nb-admin/src/main/resources/db/migration/V7__init_20251118.sql

@@ -0,0 +1 @@
+ALTER TABLE bus_clinic ADD COLUMN last_bad_eval text COMMENT '最后一次的不良评价信息';

+ 6 - 0
nb-core/pom.xml

@@ -107,5 +107,11 @@
             <groupId>com.belerweb</groupId>
             <artifactId>pinyin4j</artifactId>
         </dependency>
+        <!-- MQTT客户端依赖 -->
+        <dependency>
+            <groupId>org.eclipse.paho</groupId>
+            <artifactId>org.eclipse.paho.client.mqttv3</artifactId>
+            <version>1.2.5</version>
+        </dependency>
     </dependencies>
 </project>

+ 277 - 154
nb-core/src/main/java/com/nb/core/utils/MqttClientUtil.java

@@ -1,210 +1,333 @@
 package com.nb.core.utils;
 
-import cn.hutool.core.util.ObjectUtil;
-import cn.hutool.json.JSONUtil;
-import com.nb.core.entity.MqttMessage;
-import org.springframework.integration.channel.DirectChannel;
-import org.springframework.integration.mqtt.core.MqttPahoClientFactory;
-import org.springframework.integration.mqtt.inbound.MqttPahoMessageDrivenChannelAdapter;
-import org.springframework.integration.mqtt.outbound.MqttPahoMessageHandler;
-import org.springframework.integration.mqtt.support.DefaultPahoMessageConverter;
-import org.springframework.messaging.MessageChannel;
-import org.springframework.messaging.MessageHandler;
-import org.springframework.messaging.MessagingException;
-import org.springframework.context.ApplicationContext;
-import org.springframework.context.ApplicationContextAware;
-import org.springframework.stereotype.Component;
-import org.springframework.scheduling.annotation.Async;
-
-import javax.annotation.PostConstruct;
-import javax.annotation.PreDestroy;
-import java.util.concurrent.ConcurrentHashMap;
-import java.util.Map;
-import java.util.function.Consumer;
+import lombok.extern.slf4j.Slf4j;
+import org.eclipse.paho.client.mqttv3.*;
+import org.eclipse.paho.client.mqttv3.persist.MemoryPersistence;
+
+import java.nio.charset.StandardCharsets;
+import java.util.UUID;
+import java.util.concurrent.CompletableFuture;
 
 /**
  * MQTT客户端工具类
- * 提供MQTT连接、消息发布、订阅等功能
+ * 提供MQTT连接、消息发布、订阅等通用功能
  *
- * @author YourName
+ * @author lingma
  * @version 1.0.0
+ * @since 1.0.0
  */
-@Component
-public class MqttClientUtil implements ApplicationContextAware {
-    public static final String CLIENT_ID = "nb-netpump"+"-"+System.currentTimeMillis();
-    private ApplicationContext applicationContext;
-
-    private final Map<String, MqttPahoMessageDrivenChannelAdapter> subscribers = new ConcurrentHashMap<>();
-    
-    private MqttPahoClientFactory mqttClientFactory;
-
-    private MessageChannel mqttInputChannel;
-
-    public Boolean isOnline(){
-        return ObjectUtil.isNotNull(mqttClientFactory);
-    }
-
-    @PostConstruct
-    public void init() {
-        // 创建默认的消息通道
-        mqttInputChannel = new DirectChannel();
-        // 尝试从Spring容器中获取MqttPahoClientFactory
-        try {
-            mqttClientFactory = applicationContext.getBean(MqttPahoClientFactory.class);
-        } catch (Exception e) {
-            mqttClientFactory=null;
-            // 忽略异常,如果获取不到工厂则无法进行MQTT操作
+@Slf4j
+public class MqttClientUtil {
+
+    private MqttClient client;
+    private MqttConnectOptions options;
+    private String serverURI;
+    private String clientId;
+    private String username;
+    private String password;
+
+    /**
+     * 构造函数
+     *
+     * @param serverURI MQTT服务器地址,例如:tcp://localhost:1883
+     * @param clientId  客户端ID,需要唯一
+     */
+    public MqttClientUtil(String serverURI, String clientId) {
+        this.serverURI = serverURI;
+        this.clientId = clientId;
+    }
+
+    /**
+     * 构造函数
+     *
+     * @param serverURI MQTT服务器地址,例如:tcp://localhost:1883
+     * @param clientId  客户端ID,需要唯一
+     * @param username  用户名
+     * @param password  密码
+     */
+    public MqttClientUtil(String serverURI, String clientId, String username, String password) {
+        this(serverURI, clientId);
+        this.username = username;
+        this.password = password;
+    }
+
+    /**
+     * 初始化MQTT客户端
+     *
+     * @throws MqttException MQTT异常
+     */
+    public void init() throws MqttException {
+        if (client == null) {
+            client = new MqttClient(serverURI, clientId, new MemoryPersistence());
+        }
+
+        options = new MqttConnectOptions();
+        options.setCleanSession(true);
+        options.setConnectionTimeout(30);
+        options.setKeepAliveInterval(60);
+
+        if (username != null && password != null) {
+            options.setUserName(username);
+            options.setPassword(password.toCharArray());
+        }
+
+        client.setCallback(new MqttCallbackExtended() {
+            @Override
+            public void connectComplete(boolean reconnect, String serverURI) {
+                log.info("MQTT客户端连接完成 - serverURI: {}, clientId: {}, reconnect: {}", serverURI, clientId, reconnect);
+            }
+
+            @Override
+            public void connectionLost(Throwable cause) {
+                log.error("MQTT客户端连接丢失 - clientId: {}", clientId, cause);
+            }
+
+            @Override
+            public void messageArrived(String topic, MqttMessage message) throws Exception {
+                log.info("MQTT客户端收到消息 - topic: {}, message: {}", topic, new String(message.getPayload(), StandardCharsets.UTF_8));
+            }
+
+            @Override
+            public void deliveryComplete(IMqttDeliveryToken token) {
+                log.debug("MQTT消息发送完成 - token: {}", token);
+            }
+        });
+    }
+
+    /**
+     * 连接到MQTT服务器
+     *
+     * @throws MqttException MQTT异常
+     */
+    public void connect() throws MqttException {
+        if (client == null) {
+            init();
+        }
+        if (!client.isConnected()) {
+            client.connect(options);
+            log.info("MQTT客户端连接成功 - serverURI: {}, clientId: {}", serverURI, clientId);
         }
     }
 
-    @PreDestroy
-    public void destroy() {
-        // 清理所有订阅者
-        subscribers.values().forEach(adapter -> {
+    /**
+     * 异步连接到MQTT服务器
+     *
+     * @return CompletableFuture<Void>
+     */
+    public CompletableFuture<Void> connectAsync() {
+        return CompletableFuture.runAsync(() -> {
             try {
-                adapter.stop();
-            } catch (Exception e) {
-                // 忽略停止异常
+                connect();
+            } catch (MqttException e) {
+                log.error("MQTT客户端连接失败 - serverURI: {}, clientId: {}", serverURI, clientId, e);
+                throw new RuntimeException(e);
             }
         });
-        subscribers.clear();
     }
-    
+
+    /**
+     * 断开MQTT连接
+     *
+     * @throws MqttException MQTT异常
+     */
+    public void disconnect() throws MqttException {
+        if (client != null && client.isConnected()) {
+            client.disconnect();
+            log.info("MQTT客户端断开连接 - clientId: {}", clientId);
+        }
+    }
+
     /**
-     * 设置应用上下文
-     * @param applicationContext 应用上下文
+     * 异步断开MQTT连接
+     *
+     * @return CompletableFuture<Void>
      */
-    @Override
-    public void setApplicationContext(ApplicationContext applicationContext) {
-        this.applicationContext = applicationContext;
+    public CompletableFuture<Void> disconnectAsync() {
+        return CompletableFuture.runAsync(() -> {
+            try {
+                disconnect();
+            } catch (MqttException e) {
+                log.error("MQTT客户端断开连接失败 - clientId: {}", clientId, e);
+                throw new RuntimeException(e);
+            }
+        });
     }
-    
+
+    /**
+     * 关闭MQTT客户端
+     *
+     * @throws MqttException MQTT异常
+     */
+    public void close() throws MqttException {
+        if (client != null) {
+            if (client.isConnected()) {
+                client.disconnect();
+            }
+            client.close();
+            log.info("MQTT客户端已关闭 - clientId: {}", clientId);
+        }
+    }
+
+    /**
+     * 异步关闭MQTT客户端
+     *
+     * @return CompletableFuture<Void>
+     */
+    public CompletableFuture<Void> closeAsync() {
+        return CompletableFuture.runAsync(() -> {
+            try {
+                close();
+            } catch (MqttException e) {
+                log.error("MQTT客户端关闭失败 - clientId: {}", clientId, e);
+                throw new RuntimeException(e);
+            }
+        });
+    }
+
     /**
      * 发布消息
-     * @param topic 主题
+     *
+     * @param topic   主题
      * @param payload 消息内容
+     * @param qos     服务质量等级(0,1,2)
+     * @param retained 是否保留消息
+     * @throws MqttException MQTT异常
      */
-    public void publish(String hospitalCode,String topic, Object payload) {
-        publish(hospitalCode,topic, payload, 0, false);
+    public void publish(String topic, String payload, int qos, boolean retained) throws MqttException {
+        MqttMessage message = new MqttMessage(payload.getBytes(StandardCharsets.UTF_8));
+        message.setQos(qos);
+        message.setRetained(retained);
+        publish(topic, message);
     }
-    
+
     /**
-     * 发布消息到指定客户端
-     * @param topic 主题
+     * 发布消息
+     *
+     * @param topic   主题
+     * @param message 消息
+     * @throws MqttException MQTT异常
+     */
+    public void publish(String topic, MqttMessage message) throws MqttException {
+        checkConnected();
+        client.publish(topic, message);
+        log.debug("MQTT消息发布成功 - topic: {}", topic);
+    }
+
+    /**
+     * 异步发布消息
+     *
+     * @param topic   主题
      * @param payload 消息内容
-     * @param qos 服务质量等级
+     * @param qos     服务质量等级(0,1,2)
      * @param retained 是否保留消息
+     * @return CompletableFuture<Void>
      */
-    public void publish(String hospitalCode, String topic, Object payload, int qos, boolean retained) {
-        try {
-            if (mqttClientFactory == null) {
-                return;
+    public CompletableFuture<Void> publishAsync(String topic, String payload, int qos, boolean retained) {
+        return CompletableFuture.runAsync(() -> {
+            try {
+                publish(topic, payload, qos, retained);
+            } catch (MqttException e) {
+                log.error("MQTT消息发布失败 - topic: {}", topic, e);
+                throw new RuntimeException(e);
             }
-            
-            // 创建消息实体
-            MqttMessage message = new MqttMessage(topic, JSONUtil.toJsonStr(payload));
-            message.setClientId(CLIENT_ID);
-            
-            MqttPahoMessageHandler messageHandler = new MqttPahoMessageHandler(CLIENT_ID, mqttClientFactory);
-            messageHandler.setDefaultTopic("hospitalInfo/"+hospitalCode);
-            messageHandler.setDefaultQos(qos);
-            messageHandler.setDefaultRetained(retained);
-            // 确保处理器已初始化
-            messageHandler.afterPropertiesSet();
-            
-            org.springframework.messaging.Message<String> springMessage =
-                org.springframework.messaging.support.MessageBuilder.withPayload(JSONUtil.toJsonStr(message)).build();
-            messageHandler.handleMessage(springMessage);
-        } catch (Exception e) {
-            throw new RuntimeException("发布MQTT消息失败: " + e.getMessage(), e);
-        }
+        });
     }
 
-    
     /**
      * 订阅主题
+     *
      * @param topic 主题
-     * @param messageHandler 消息处理器
+     * @param qos   服务质量等级
+     * @throws MqttException MQTT异常
      */
-    public void subscribe(String topic, MessageHandler messageHandler) {
-        try {
-            if (mqttClientFactory == null) {
-                return;
-            }
-            // 如果已经订阅了该主题,则先取消订阅
-            if (subscribers.containsKey(topic)) {
-                unsubscribe(topic);
-            }
-            
-            MqttPahoMessageDrivenChannelAdapter adapter = 
-                new MqttPahoMessageDrivenChannelAdapter(CLIENT_ID, mqttClientFactory, topic);
-            adapter.setConverter(new DefaultPahoMessageConverter());
-            adapter.setOutputChannel(mqttInputChannel);
-            
-            // 创建一个带有处理逻辑的通道
-            DirectChannel channel = new DirectChannel();
-            channel.subscribe(messageHandler);
-            adapter.setOutputChannel(channel);
-            
-            adapter.start();
-            
-            subscribers.put(topic, adapter);
-        } catch (Exception e) {
-            throw new RuntimeException("订阅MQTT主题失败: " + e.getMessage(), e);
-        }
+    public void subscribe(String topic, int qos) throws MqttException {
+        checkConnected();
+        client.subscribe(topic, qos);
+        log.info("MQTT订阅主题成功 - topic: {}, qos: {}", topic, qos);
     }
-    
+
     /**
-     * 订阅主题(使用函数式接口处理消息)
+     * 异步订阅主题
+     *
      * @param topic 主题
-     * @param messageConsumer 消息消费者
+     * @param qos   服务质量等级
+     * @return CompletableFuture<Void>
      */
-    public void subscribe(String topic, Consumer<String> messageConsumer) {
-        MessageHandler handler = new MessageHandler() {
-            @Override
-            public void handleMessage(org.springframework.messaging.Message<?> message) throws MessagingException {
-                String payload = new String((byte[]) message.getPayload());
-                messageConsumer.accept(payload);
+    public CompletableFuture<Void> subscribeAsync(String topic, int qos) {
+        return CompletableFuture.runAsync(() -> {
+            try {
+                subscribe(topic, qos);
+            } catch (MqttException e) {
+                log.error("MQTT订阅主题失败 - topic: {}", topic, e);
+                throw new RuntimeException(e);
             }
-        };
-        subscribe(topic, handler);
+        });
     }
-    
+
     /**
-     * 取消订阅
+     * 取消订阅主题
+     *
      * @param topic 主题
+     * @throws MqttException MQTT异常
      */
-    public void unsubscribe(String topic) {
-        MqttPahoMessageDrivenChannelAdapter adapter = subscribers.get(topic);
-        if (adapter != null) {
+    public void unsubscribe(String topic) throws MqttException {
+        checkConnected();
+        client.unsubscribe(topic);
+        log.info("MQTT取消订阅主题成功 - topic: {}", topic);
+    }
+
+    /**
+     * 异步取消订阅主题
+     *
+     * @param topic 主题
+     * @return CompletableFuture<Void>
+     */
+    public CompletableFuture<Void> unsubscribeAsync(String topic) {
+        return CompletableFuture.runAsync(() -> {
             try {
-                adapter.stop();
-            } catch (Exception e) {
-                // 忽略停止异常
+                unsubscribe(topic);
+            } catch (MqttException e) {
+                log.error("MQTT取消订阅主题失败 - topic: {}", topic, e);
+                throw new RuntimeException(e);
             }
-            subscribers.remove(topic);
+        });
+    }
+
+    /**
+     * 检查客户端是否连接
+     *
+     * @throws MqttException MQTT异常
+     */
+    private void checkConnected() throws MqttException {
+        if (client == null || !client.isConnected()) {
+            throw new MqttException(MqttException.REASON_CODE_CLIENT_NOT_CONNECTED);
         }
     }
 
     /**
-     * 异步发布消息
-     * @param topic 主题
-     * @param payload 消息内容
+     * 获取客户端ID
+     *
+     * @return 客户端ID
      */
-    @Async
-    public void asyncPublish(String hospitalCode,String topic, Object payload) {
-        publish(hospitalCode,topic, payload);
+    public String getClientId() {
+        return clientId;
     }
 
     /**
-     * 异步发布消息到指定客户端
-     * @param topic 主题
-     * @param payload 消息内容
-     * @param qos 服务质量等级
-     * @param retained 是否保留消息
+     * 获取MQTT客户端
+     *
+     * @return MqttClient
+     */
+    public MqttClient getClient() {
+        return client;
+    }
+
+    /**
+     * 生成随机客户端ID
+     *
+     * @return 随机客户端ID
      */
-    @Async
-    public void asyncPublish(String hospitalCode, String topic, String payload, int qos, boolean retained) {
-        publish(hospitalCode, topic, payload, qos, retained);
+    public static String generateClientId() {
+        return "mqtt_client_" + UUID.randomUUID().toString().replace("-", "");
     }
 }

+ 35 - 60
nb-core/src/test/java/com/nb/core/utils/MqttClientUtilTest.java

@@ -1,82 +1,57 @@
 package com.nb.core.utils;
 
-import cn.hutool.core.map.MapUtil;
-import cn.hutool.core.util.ReflectUtil;
-import org.eclipse.paho.client.mqttv3.MqttConnectOptions;
+import lombok.extern.slf4j.Slf4j;
+import org.eclipse.paho.client.mqttv3.MqttException;
 import org.junit.jupiter.api.Test;
-import org.mockito.Mock;
-import org.springframework.context.ApplicationContext;
-import org.springframework.integration.mqtt.core.DefaultMqttPahoClientFactory;
-import org.springframework.integration.mqtt.core.MqttPahoClientFactory;
 
+import java.util.concurrent.CompletableFuture;
+import java.util.concurrent.ExecutionException;
+import java.util.concurrent.TimeUnit;
+import java.util.concurrent.TimeoutException;
 
 /**
- * MqttClientUtil测试类
+ * MQTT客户端工具类测试
  *
- * @author YourName
+ * @author lingma
  * @version 1.0.0
+ * @since 1.0.0
  */
+@Slf4j
 public class MqttClientUtilTest {
 
-    @Mock
-    private ApplicationContext applicationContext;
-
     @Test
-    public void testPublish() {
-        MqttClientUtil mqttClientUtil = new MqttClientUtil();
-        mqttClientUtil.setApplicationContext(applicationContext);
-        ReflectUtil.setFieldValue(mqttClientUtil, "mqttClientFactory", createDefaultClientFactory());
+    public void testMqttClient() throws MqttException, ExecutionException, InterruptedException, TimeoutException {
+        // 创建MQTT客户端
+        MqttClientUtil mqttClient = new MqttClientUtil(
+                "tcp://broker.emqx.io:1883",
+                MqttClientUtil.generateClientId()
+        );
 
-        // 测试发布消息
         try {
-            mqttClientUtil.publish("1000","testtopic/123", MapUtil.builder()
-                            .put("test","123")
-                    .build());
-        } catch (Exception e) {
-            e.printStackTrace();
-            // 在测试环境中,由于没有实际的MQTT服务器,会抛出异常,这是预期的
-        }
-    }
+            // 初始化客户端
+            mqttClient.init();
 
-    @Test
-    public void testPublishWithParams() {
-        MqttClientUtil mqttClientUtil = new MqttClientUtil();
-        mqttClientUtil.setApplicationContext(applicationContext);
-        
-        // 测试发布消息(带参数)
-        try {
-            mqttClientUtil.publish("1000","test/topic", "Hello MQTT", 1, false);
-        } catch (Exception e) {
-            // 在测试环境中,由于没有实际的MQTT服务器,会抛出异常,这是预期的
-        }
-    }
+            // 连接服务器
+            CompletableFuture<Void> connectFuture = mqttClient.connectAsync();
+            connectFuture.get(10, TimeUnit.SECONDS); // 等待连接完成,最多10秒
 
+            // 订阅主题
+            CompletableFuture<Void> subscribeFuture = mqttClient.subscribeAsync("test/topic", 1);
+            subscribeFuture.get(5, TimeUnit.SECONDS); // 等待订阅完成,最多5秒
 
-    private String defaultBrokerUrl = "tcp://iot.tuoren.com:1883";
+            // 发布消息
+            CompletableFuture<Void> publishFuture = mqttClient.publishAsync("test/topic", "Hello MQTT!", 1, false);
+            publishFuture.get(5, TimeUnit.SECONDS); // 等待发布完成,最多5秒
 
-    private String defaultUsername = "hospital";
+            // 等待一段时间以接收消息
+            Thread.sleep(3000);
 
-    private String defaultPassword = "1qaz!QAZ";
-    /**
-     * 创建默认的客户端工厂
-     * @return MqttPahoClientFactory
-     */
-    private MqttPahoClientFactory createDefaultClientFactory() {
-        DefaultMqttPahoClientFactory factory = new DefaultMqttPahoClientFactory();
-        MqttConnectOptions options = new MqttConnectOptions();
-        options.setServerURIs(new String[]{defaultBrokerUrl});
-        options.setCleanSession(true);
-        options.setConnectionTimeout(30);
-        options.setKeepAliveInterval(60);
-        if (defaultUsername != null && !defaultUsername.isEmpty()) {
-            options.setUserName(defaultUsername);
-        }
-        if (defaultPassword != null && !defaultPassword.isEmpty()) {
-            options.setPassword(defaultPassword.toCharArray());
+        } catch (Exception e) {
+            log.error("MQTT测试出现异常", e);
+        } finally {
+            // 关闭客户端
+            CompletableFuture<Void> closeFuture = mqttClient.closeAsync();
+            closeFuture.get(5, TimeUnit.SECONDS); // 等待关闭完成,最多5秒
         }
-        // 设置自动重连
-        options.setAutomaticReconnect(true);
-        factory.setConnectionOptions(options);
-        return factory;
     }
 }

+ 30 - 0
nb-service-api/web-service-api/src/main/java/com/nb/web/api/dto/EvalBatchDTO.java

@@ -0,0 +1,30 @@
+package com.nb.web.api.dto;
+
+import com.nb.web.api.entity.BusEvaluationEntity;
+import io.swagger.annotations.ApiModel;
+import io.swagger.annotations.ApiModelProperty;
+import lombok.Data;
+
+import javax.validation.constraints.NotEmpty;
+import javax.validation.constraints.NotNull;
+import java.util.List;
+
+/**
+ * @author lingma
+ * @version 1.0.0
+ * @ClassName EvalBatchQuery.java
+ * @Description 批量评价查询参数
+ * @createTime 2025年11月18日 15:30:00
+ */
+@Data
+@ApiModel("批量评价查询参数")
+public class EvalBatchDTO {
+
+    @ApiModelProperty("评价信息")
+    @NotNull(message = "评价信息不能为空")
+    private BusEvaluationEntity evaluation;
+
+    @ApiModelProperty("临床id集合")
+    @NotEmpty(message = "临床id集合不能为空")
+    private List<String> clinicIds;
+}

+ 3 - 0
nb-service-api/web-service-api/src/main/java/com/nb/web/api/entity/BusClinicEntity.java

@@ -182,6 +182,9 @@ public class BusClinicEntity extends TenantGenericEntity<String,String> {
     @ApiModelProperty(value = "废液处理方式")
     private String liquidMethod;
 
+    @ApiModelProperty("最后一次的不良评价信息")
+    private String lastBadEval;
+
     public String getWeight() {
         return StrUtil.isBlank(weight)?null:weight;
     }

+ 9 - 2
nb-service-api/web-service-api/src/main/java/com/nb/web/api/feign/IClinicEvalClient.java

@@ -1,7 +1,7 @@
 package com.nb.web.api.feign;
 
+import com.nb.web.api.dto.EvalBatchDTO;
 import com.nb.web.api.entity.BusEvaluationEntity;
-import com.nb.web.api.feign.query.EvalQuery;
 import java.util.*;
 /**
  * @author lifang
@@ -28,4 +28,11 @@ public interface IClinicEvalClient {
       * @return boolean
       */
      boolean save(BusEvaluationEntity entity) ;
-}
+
+    /**
+     * 批量保存评价信息
+     * @param query 批量评价查询参数
+     * @return Boolean
+     */
+    Boolean saveBatchEval(EvalBatchDTO query);
+}

+ 6 - 3
nb-service-api/web-service-api/src/main/java/com/nb/web/api/feign/result/DoctorPatientMonitorResult.java

@@ -132,9 +132,6 @@ public class DoctorPatientMonitorResult implements Serializable {
     @ApiModelProperty(value = "输注开始时间,即本次运行开机时间")
     private Date infusionStartTime;
 
-    @ApiModelProperty("监控开始时间")
-    private Date monitorStartTime;
-
     @ApiModelProperty(value = "泵类型")
     private DeviceTypeEnum deviceType;
 
@@ -172,6 +169,11 @@ public class DoctorPatientMonitorResult implements Serializable {
     @ApiModelProperty("评价状态 1、已评价 2、待评价 3、未评价")
     private Integer evaluate=3;
 
+    @ApiModelProperty("手术开始监控时间")
+    private Date monitorStartTime;
+
+    @ApiModelProperty("最后一次不良评价信息")
+    private String lastBadEval;
     private void judgeWarnWillFinished() {
         if(!Boolean.TRUE.equals(this.warnWillFinished)){
             return;
@@ -224,6 +226,7 @@ public class DoctorPatientMonitorResult implements Serializable {
     }
 
     public String getWarns() {
+        handleWarn();
         if (StrUtil.isNotEmpty(warns)) {
             return warns.endsWith(";")?warns.substring(0,warns.length()-1):warns;
         }

+ 1 - 8
nb-service/app-doctor/src/main/java/com/nb/app/doctor/auth/AppDoctorUserAccountOperator.java

@@ -6,7 +6,6 @@ import cn.hutool.core.bean.BeanUtil;
 import cn.hutool.core.util.ObjectUtil;
 import cn.hutool.core.util.StrUtil;
 import cn.hutool.json.JSONUtil;
-import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
 import com.baomidou.mybatisplus.core.conditions.update.UpdateWrapper;
 import com.nb.app.doctor.controller.vo.DoctorUserVo;
 import com.nb.app.doctor.api.entity.AppDoctorUserEntity;
@@ -18,7 +17,6 @@ import com.nb.auth.controller.vo.UserInfoVO;
 import com.nb.auth.enums.GrantTypeEnum;
 import com.nb.auth.granter.IAccountOperator;
 import com.nb.auth.utils.SecurityUtil;
-import com.nb.common.config.annotation.TenantIgnore;
 import com.nb.common.config.context.TenantContextHolder;
 import com.nb.core.exception.CustomException;
 import lombok.AllArgsConstructor;
@@ -45,14 +43,9 @@ public class AppDoctorUserAccountOperator implements IAccountOperator<DoctorUser
     }
 
     @Override
-    @TenantIgnore
     public UserInfoVO getUserInfo() {
         UserInfoVO userInfoVO = new UserInfoVO();
-        AppDoctorUserEntity user = doctorUserService.getOne(new LambdaQueryWrapper<AppDoctorUserEntity>()
-                        .eq(AppDoctorUserEntity::getUsername, SecurityUtil.getUsername())
-                        .eq(AppDoctorUserEntity::getTenantId, SecurityUtil.getTenantId())
-                .last("limit 1")
-              );
+        AppDoctorUserEntity user = doctorUserService.getById(SecurityUtil.getStpLogic().getLoginIdAsString());
         if(ObjectUtil.isNull(user)){
             StpLogic stpLogic = SecurityUtil.getStpLogic();
             stpLogic.logout();

+ 2 - 4
nb-service/app-doctor/src/main/java/com/nb/app/doctor/controller/EvalController.java

@@ -10,7 +10,6 @@ import com.nb.core.entity.GenericEntity;
 import com.nb.core.result.R;
 import com.nb.web.api.dto.EvalBatchDTO;
 import com.nb.web.api.entity.BusEvaluationEntity;
-import com.nb.web.api.entity.BusHospitalConfigEntity;
 import com.nb.web.api.feign.IClinicEvalClient;
 import com.nb.web.api.feign.IHospitalConfigClient;
 import io.swagger.annotations.Api;
@@ -22,7 +21,6 @@ import org.springframework.web.bind.annotation.*;
 
 import java.util.LinkedList;
 import java.util.List;
-import java.util.Optional;
 
 /**
  * @author lifang
@@ -77,8 +75,8 @@ public class EvalController {
 
     @PostMapping("/config/{tenantId}")
     @ApiOperation("获取评价信息配置项")
-    public R<BusHospitalConfigEntity> config(@PathVariable("tenantId") String tenantId){
-        return R.success(Optional.ofNullable(configClient.getEvalConfig(tenantId)).orElse(new BusHospitalConfigEntity()));
+    public R config(@PathVariable("tenantId") String tenantId){
+        return R.success(configClient.getEvalConfig(tenantId));
     }
 
     @PostMapping("/batch")

+ 12 - 3
nb-service/app-doctor/src/main/java/com/nb/app/doctor/controller/UserController.java

@@ -1,6 +1,7 @@
 package com.nb.app.doctor.controller;
 
 import cn.dev33.satoken.session.SaSession;
+import cn.hutool.core.collection.CollectionUtil;
 import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
 import com.nb.app.doctor.api.entity.AppUserConsultConfigEntity;
 import com.nb.app.doctor.service.dto.UserShiftHospitalDTO;
@@ -19,6 +20,8 @@ import lombok.extern.slf4j.Slf4j;
 import org.springframework.validation.annotation.Validated;
 import org.springframework.web.bind.annotation.*;
 import java.util.*;
+import java.util.stream.Collectors;
+
 /**
  * @author lifang
  * @version 1.0.0
@@ -60,6 +63,14 @@ public class UserController {
     @ApiOperation("切换当前用户所在医院")
     @TenantIgnore
     public R<Boolean> shiftHospital(@RequestBody@Validated UserShiftHospitalDTO source){
+        List<AppHospitalVO> appHospitalVOS = hospitalClient.selectUserHospitalList(SecurityUtil.getUsername());
+        if(CollectionUtil.isEmpty(appHospitalVOS)){
+            throw new RuntimeException("当前用户没有医院信息");
+        }
+        Set<String> hospitalIdSets = appHospitalVOS.stream().map(AppHospitalVO::getId).collect(Collectors.toSet());
+        if(!hospitalIdSets.contains(source.getHospitalId())){
+            throw new RuntimeException("当前用户没有此医院信息");
+        }
         SaSession tokenSession = SecurityUtil.getStpLogic().getTokenSessionByToken(SecurityUtil.getStpLogic().getTokenValue());
         LoginUser<String> loginUserClass =tokenSession.getModel(SecurityUtil.LOGIN_USER_KEY, LoginUser.class);
         String hospitalId = source.getHospitalId();
@@ -67,6 +78,4 @@ public class UserController {
         tokenSession.set(SecurityUtil.LOGIN_USER_KEY, loginUserClass);
         return R.success(Boolean.TRUE);
     }
-
-
-}
+}

+ 6 - 0
nb-service/web-service/pom.xml

@@ -109,5 +109,11 @@
             <artifactId>spring-boot-starter-amqp</artifactId>
         </dependency>
 
+        <dependency>
+            <groupId>org.springframework.boot</groupId>
+            <artifactId>spring-boot-starter-test</artifactId>
+            <scope>test</scope>
+        </dependency>
+
     </dependencies>
 </project>

+ 9 - 1
nb-service/web-service/src/main/java/com/nb/web/service/bus/controller/BusEvaluationController.java

@@ -6,6 +6,7 @@ import com.baomidou.mybatisplus.core.mapper.Mapper;
 import com.baomidou.mybatisplus.core.metadata.IPage;
 import com.nb.core.exception.CustomException;
 import com.nb.core.utils.ExcelUtil;
+import com.nb.web.api.dto.EvalBatchDTO;
 import com.nb.web.api.entity.BusEvaluationEntity;
 import com.nb.web.service.bus.service.LocalBusEvaluationService;
 import com.nb.web.api.feign.query.EvalQuery;
@@ -61,6 +62,13 @@ public class BusEvaluationController extends BaseCrudController<BusEvaluationEnt
         return R.success(evaluationService.pageQuery(query));
     }
 
+    @PostMapping("/batch")
+    @SaCheckPermission({"*:eval:add"})
+    @ApiOperation(value = "批量新增评价信息", notes = "权限:【*:eval:add】")
+    public R<Boolean> batchAdd(@RequestBody @Validated EvalBatchDTO source) {
+        return R.success(evaluationService.saveBatchEval(source));
+    }
+
     @PostMapping("/combine/page")
     @SaCheckPermission({"*:eval:query"})
     @ApiOperation(value = "评价查询(此查询中包括了所属的临床信息)",notes = "权限【*:eval:query】")
@@ -93,4 +101,4 @@ public class BusEvaluationController extends BaseCrudController<BusEvaluationEnt
     public BaseService<? extends Mapper<BusEvaluationEntity>, BusEvaluationEntity, String> getService() {
         return evaluationService;
     }
-}
+}

+ 8 - 50
nb-service/web-service/src/main/java/com/nb/web/service/bus/service/LocalBusEvaluationService.java

@@ -2,23 +2,18 @@ package com.nb.web.service.bus.service;
 
 import cn.hutool.core.collection.CollectionUtil;
 import cn.hutool.core.text.CharSequenceUtil;
-import cn.hutool.core.util.ObjectUtil;
 import cn.hutool.core.util.StrUtil;
+import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
 import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
 import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper;
+import com.baomidou.mybatisplus.core.conditions.update.UpdateWrapper;
 import com.baomidou.mybatisplus.core.metadata.IPage;
-import com.nb.auth.utils.SecurityUtil;
-import com.nb.core.enums.MqttTopicEnum;
-import com.nb.core.utils.MqttClientUtil;
 import com.nb.web.api.dto.EvalBatchDTO;
 import com.nb.web.api.entity.BusClinicEntity;
 import com.nb.web.api.entity.BusEvaluationEntity;
 import com.nb.web.api.feign.IClinicEvalClient;
-import com.nb.web.api.feign.IHospitalClient;
-import com.nb.web.service.bus.entity.BusPatientEntity;
 import com.nb.web.service.bus.mapper.BusEvaluationMapper;
 import com.nb.web.api.feign.query.EvalQuery;
-import com.nb.web.service.bus.mapper.BusPatientMapper;
 import com.nb.web.service.bus.utils.AdverseReactionUtil;
 import com.nb.web.service.bus.utils.WsPublishUtils;
 import com.nb.common.crud.BaseService;
@@ -51,14 +46,6 @@ public class LocalBusEvaluationService extends BaseService<BusEvaluationMapper,
     @Lazy
     private WsPublishUtils wsPublishUtils;
 
-    @Autowired
-    private BusPatientMapper patientMapper;
-
-    @Autowired
-    private MqttClientUtil mqttClientUtil;
-
-    @Autowired
-    private IHospitalClient hospitalClient;
 
     public IPage<BusEvaluationEntity> pageQuery(EvalQuery query) {
         return this.baseMapper.pageQuery(query.getPage(),query);
@@ -133,40 +120,15 @@ public class LocalBusEvaluationService extends BaseService<BusEvaluationMapper,
 
     @Override
     public void validateBeforeSave(BusEvaluationEntity entity) {
-        BusClinicEntity clinic=null;
-        String clinicId = entity.getClinicId();
-        if (StrUtil.isEmpty(entity.getPatientCode())) {
-            clinic = clinicService.getById(clinicId);
+        if(StrUtil.isEmpty(entity.getPatientId())){
+            String clinicId = entity.getClinicId();
+            BusClinicEntity clinic = clinicService.getById(clinicId);
             if(clinic==null){
                 throw new CustomException("临床id不能为空");
             }
-            entity.setPatientCode(clinic.getPatientCode());
-        }
-        if(StrUtil.isEmpty(entity.getPatientId())){
-            if (ObjectUtil.isNull(clinic)) {
-                clinic = clinicService.getById(clinicId);
-                if(clinic==null){
-                    throw new CustomException("临床id不能为空");
-                }
-            }
             entity.setPatientId(clinic.getPatientId());
         }
-        if(StrUtil.isEmpty(entity.getInfusionId())&&StrUtil.isNotEmpty(entity.getPatientId())){
-            BusPatientEntity patient = patientMapper.selectById(entity.getPatientId());
-            if(patient==null){
-                return;
-            }
-            entity.setInfusionId(patient.getInfusionId());
-        }
-        try {
-            String hospitalCode = hospitalClient.selectHospitalCode(SecurityUtil.getTenantId());
-            if (StrUtil.isNotEmpty(hospitalCode)) {
-                //发布消息
-                mqttClientUtil.asyncPublish(hospitalCode, MqttTopicEnum.BUS_EVALUATION,entity);
-            }
-        }catch (Exception e){
 
-        }
     }
 
     @Override
@@ -177,13 +139,9 @@ public class LocalBusEvaluationService extends BaseService<BusEvaluationMapper,
     @Override
     public void postSave(BusEvaluationEntity entity) {
         if(StrUtil.isNotEmpty(entity.getClinicId())){
-            String adverseReactions = AdverseReactionUtil.getAdverseReactions(entity);
-            String clinicId = entity.getClinicId();
-            BusClinicEntity clinic = clinicService.getById(clinicId);
-            clinic.setLastBadEval(adverseReactions);
-            clinic.setEvalTime(Optional.ofNullable(entity.getEvaluateTime()).orElse(new Date()));
-            clinic.setAbnormal(StrUtil.isNotEmpty(adverseReactions));
-            clinicService.updateById(clinic);
+            clinicService.update(new UpdateWrapper<BusClinicEntity>().lambda()
+                    .eq(BusClinicEntity::getId,entity.getClinicId())
+                    .set(BusClinicEntity::getEvalTime, Optional.ofNullable(entity.getEvaluateTime()).orElse(new Date())));
             if(CharSequenceUtil.isNotBlank(entity.getPatientId())){
                 wsPublishUtils.publishPatientMonitor(entity.getPatientId(),entity.getTenantId());
             }

+ 0 - 8
nb-service/web-service/src/main/java/com/nb/web/service/bus/service/LocalBusPatientService.java

@@ -18,11 +18,7 @@ import com.baomidou.mybatisplus.core.metadata.IPage;
 import com.baomidou.mybatisplus.core.toolkit.IdWorker;
 import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
 import com.nb.app.assistant.api.feign.result .ContactQuery;
-import com.nb.app.doctor.api.entity.AppDoctorUserEntity;
-import com.nb.app.doctor.api.entity.AppUserConsultConfigEntity;
 import com.nb.app.doctor.api.feign.IAppDoctorUserClient;
-import com.nb.app.doctor.api.feign.IAppUserConsultConfigClient;
-import com.nb.app.doctor.api.feign.result.AppDoctorUserResult;
 import com.nb.auth.utils.SecurityUtil;
 import com.nb.web.api.dto.BusPatientAbnormalMarkDTO;
 import com.nb.web.api.entity.BusClinicEntity;
@@ -55,9 +51,7 @@ import com.nb.common.crud.BaseService;
 import com.nb.core.exception.CustomException;
 import com.nb.core.result.R;
 import com.nb.core.utils.ExceptionUtil;
-import jdk.nashorn.internal.objects.NativeDebug;
 import lombok.extern.slf4j.Slf4j;
-import org.apache.tomcat.util.net.openssl.ciphers.Authentication;
 import org.springframework.beans.factory.annotation.Autowired;
 import org.springframework.context.annotation.Lazy;
 import org.springframework.stereotype.Service;
@@ -66,7 +60,6 @@ import org.springframework.transaction.annotation.Propagation;
 import org.springframework.transaction.annotation.Transactional;
 import org.springframework.web.context.request.async.DeferredResult;
 
-import javax.servlet.http.HttpSession;
 import javax.validation.constraints.NotNull;
 import java.time.LocalDateTime;
 import java.time.ZoneOffset;
@@ -75,7 +68,6 @@ import java.util.concurrent.CompletableFuture;
 import java.util.concurrent.Executors;
 import java.util.concurrent.ScheduledExecutorService;
 import java.util.concurrent.TimeUnit;
-import java.util.stream.Collector;
 import java.util.stream.Collectors;
 
 /**

+ 3 - 1
nb-service/web-service/src/main/resources/mapper/bus/BusPatientMapper.xml

@@ -559,6 +559,7 @@
         <result column="assist_nickname" property="assistNickname"/>
         <result column="abnormal" property="abnormal"/>
         <result column="monitor_start_time" property="monitorStartTime"/>
+        <result column="last_bad_eval" property="lastBadEval"/>
     </resultMap>
     <select id="doctorSelectPatientList" resultMap="doctorMonitorResult">
         SELECT
@@ -615,7 +616,8 @@
             aub.assist_id as assist_id,
             aub.assist_nickname as assist_nickname,
         </if>
-        i.warn_will_finished AS warn_will_finished
+        i.warn_will_finished AS warn_will_finished,
+        c.last_bad_eval as last_bad_eval
         FROM
         bus_patient p
         JOIN bus_clinic c ON p.clinic_id = c.id          <!-- 患者与临床信息关联 -->