Переглянути джерело

update
即时通讯智能体

lifang 3 місяців тому
батько
коміт
64f1de32cb

+ 204 - 0
tr-modules/tr-module-smartFollowUp/src/main/java/cn/tr/module/smart/common/config/MpMsgPushListener.java

@@ -0,0 +1,204 @@
+package cn.tr.module.smart.common.config;
+
+import cn.hutool.core.util.ObjectUtil;
+import cn.hutool.core.util.StrUtil;
+import cn.tr.core.annotation.TenantIgnore;
+import cn.tr.core.utils.JsonUtils;
+import cn.tr.module.api.sys.tenant.SysTenantApi;
+import cn.tr.module.api.sys.tenant.SysTenantPojo;
+import cn.tr.module.smart.common.dto.NbPumpInfusionDTO;
+import cn.tr.module.smart.common.enums.FlowStatusEnum;
+import cn.tr.module.smart.common.enums.InfusionBindType;
+import cn.tr.module.smart.common.enums.RabbitMQConstant;
+import cn.tr.module.smart.common.mapper.BizDeviceAlarmMapper;
+import cn.tr.module.smart.common.mapper.BizDeviceHistoryMapper;
+import cn.tr.module.smart.common.mapper.BizDeviceMapper;
+import cn.tr.module.smart.common.mapper.BizInfusionHistoryMapper;
+import cn.tr.module.smart.common.po.*;
+import cn.tr.module.smart.common.repository.*;
+import cn.tr.plugin.security.bo.UserLoginInfoBO;
+import cn.tr.plugin.security.context.LoginUserContextHolder;
+import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
+import lombok.AllArgsConstructor;
+import lombok.extern.slf4j.Slf4j;
+import org.springframework.amqp.rabbit.annotation.RabbitListener;
+import org.springframework.stereotype.Service;
+import org.springframework.transaction.annotation.Transactional;
+
+import java.util.Arrays;
+import java.util.List;
+import java.util.Objects;
+import java.util.function.BiFunction;
+import java.util.function.Function;
+
+/**
+ * 公众号消息推送
+ */
+@Slf4j
+@Service
+@AllArgsConstructor
+public class MpMsgPushListener {
+    private final SysTenantApi sysTenantApi;
+    private final BizInfusionClinicRepository infusionClinicRepository;
+    private final BizInfusionHistoryRepository infusionHistoryRepository;
+    private final BizPatientRepository patientRepository;
+    private final BizDeviceHistoryRepository deviceHistoryRepository;
+    private final BizDeviceRepository deviceRepository;
+    private final BizDeviceAlarmRepository deviceAlarmRepository;
+    @RabbitListener(queues = RabbitMQConstant.QUEUE_PATIENT_MONITOR)
+    @TenantIgnore
+    @Transactional(rollbackFor = Exception.class)
+    public void handlePatientMonitorMessage(String message) {
+        UserLoginInfoBO userLoginInfoBO = new UserLoginInfoBO();
+        userLoginInfoBO.setUserId("1");
+        LoginUserContextHolder.setUser(userLoginInfoBO);
+        log.debug("接收到网络泵消息: {}", message);
+        // 在这里处理接收到的消息
+        processPatientMonitorData(message);
+    }
+
+    private void processPatientMonitorData(String message) {
+        log.info("开始处理患者监护数据");
+
+        // 解析消息为NbPumpInfusionDTO对象
+        NbPumpInfusionDTO source = JsonUtils.parseObject(message, NbPumpInfusionDTO.class);
+        if (ObjectUtil.isNull(source)) {
+            log.warn("无法解析患者监护消息,消息内容: {}", message);
+            return;
+        }
+        log.debug("成功解析网络泵数据: {}", source);
+
+        // 根据医院编码查找租户信息
+        log.debug("开始查找医院信息,医院编码: {}", source.getHospitalCode());
+        SysTenantPojo tenant = sysTenantApi.selectByHospitalCode(source.getHospitalCode());
+        if(ObjectUtil.isNull(tenant)){
+            log.warn("未找到医院编码: {}", source.getHospitalCode());
+            return;
+        }
+        log.debug("成功找到医院信息,医院名称: {}, 租户ID: {}", tenant.getName(), tenant.getTenantId());
+        BizInfusionHistoryPO infusionHistory = BizInfusionHistoryMapper.INSTANCE.convertPO(source);
+        BizDeviceHistoryPO deviceHistory = BizDeviceHistoryMapper.INSTANCE.convertPO(source);
+
+        infusionHistory.setTenantId(tenant.getTenantId());
+        deviceHistory.setTenantId(tenant.getTenantId());
+
+        deviceHistoryRepository.insert(deviceHistory);
+        log.debug("开始保存或更新输液历史记录,记录ID: {}", infusionHistory.getId());
+        BizInfusionHistoryPO oldInfusionHistory = infusionHistoryRepository.selectById(infusionHistory.getId());
+        if (ObjectUtil.isNotNull(oldInfusionHistory)) {
+            log.debug("更新已存在的输液历史记录");
+            infusionHistoryRepository.updateById(infusionHistory);
+        }else {
+            log.debug("插入新的输液历史记录");
+            infusionHistoryRepository.insert(infusionHistory);
+        }
+        log.info("输液历史记录保存完成");
+        //保存或者记录设备信息
+        BizDevicePO device = BizDeviceMapper.INSTANCE.convertPO(source);
+        device.setTenantId(tenant.getTenantId());
+        BizDevicePO oldDevice = deviceRepository.selectById(device);
+        if (ObjectUtil.isNotNull(oldDevice)) {
+            log.debug("更新已存在的设备记录");
+            deviceRepository.updateById(device);
+        }else {
+            log.debug("插入新的设备记录");
+            deviceRepository.insert(device);
+        }
+        //处理设备报警信息
+        BizDeviceAlarmPO bizDeviceAlarmPO = handleAlarmData(infusionHistory,oldInfusionHistory, deviceHistory);
+        if(ObjectUtil.isNotNull(bizDeviceAlarmPO)){
+            deviceAlarmRepository.insert(bizDeviceAlarmPO);
+        }
+        // 根据住院号查找患者信息
+        log.debug("开始精确查找患者信息,住院号: {}", source.getPatientCode());
+        BizPatientPO patientPO=patientRepository.selectOne(new LambdaQueryWrapper<BizPatientPO>()
+                .eq(BizPatientPO::getPatientCode, source.getPatientCode())
+                .eq(BizPatientPO::getTenantId,tenant.getTenantId())
+                .last("limit 1"));
+
+        // 如果精确查找未找到,则进行模糊查找
+        if(ObjectUtil.isNull(patientPO)){
+            log.debug("精确查找未找到患者,开始模糊查找,住院号: {}", infusionHistory.getPatientCode());
+            patientPO=patientRepository.selectMayBeLinkedPatient(infusionHistory.getPatientCode(),infusionHistory.getTenantId());
+        }
+        // 如果找到相似的住院号
+        if (ObjectUtil.isNotNull(patientPO)) {
+            BizInfusionClinicPO infusionClinic = new BizInfusionClinicPO();
+            infusionClinic.setInfusionId(infusionHistory.getId());
+            infusionClinic.setClinicId(patientPO.getCurrentClinicId());
+            infusionClinic.setType(InfusionBindType.autoBind);
+            //判断有没有被绑定
+            BizInfusionClinicPO infusionClinicPO = infusionClinicRepository.selectOne(new LambdaQueryWrapper<BizInfusionClinicPO>()
+                    .eq(BizInfusionClinicPO::getClinicId, patientPO.getCurrentClinicId())
+                    .last("limit 1"));
+            if(StrUtil.equals(infusionClinicPO.getInfusionId(),infusionHistory.getId())){
+                //已绑定
+                return;
+            }
+            if (ObjectUtil.isNotNull(infusionClinicPO)) {
+                if(InfusionBindType.autoBind.equals(infusionClinicPO.getType())){
+                    //如果是自动绑的,则判断两个泵头的先后顺序
+                    BizInfusionHistoryPO preInfusionHistory = infusionHistoryRepository.selectById(infusionClinicPO.getInfusionId());
+                    if (ObjectUtil.isNotNull(preInfusionHistory)) {
+                        infusionClinicRepository.deleteById(infusionClinicPO.getId());
+                        infusionClinicRepository.insert(infusionClinic);
+                        log.info("找到匹配的患者信息,患者ID: {}", patientPO.getId());
+                    }else {
+                        if(ObjectUtil.compare(infusionHistory.getInfusionStartTime(),preInfusionHistory.getInfusionStartTime())>0){
+                            infusionClinicRepository.deleteById(infusionClinicPO.getId());
+                            infusionClinicRepository.insert(infusionClinic);
+                            log.info("找到匹配的患者信息,患者ID: {}", patientPO.getId());
+                        }
+                    }
+                }
+            }else {
+                infusionClinicRepository.insert(infusionClinic);
+                log.info("找到匹配的患者信息,患者ID: {}", patientPO.getId());
+            }
+        } else {
+            log.warn("未找到匹配的患者信息,住院号: {}", source.getPatientCode());
+        }
+
+        log.info("患者监护数据处理完成");
+    }
+
+    /**
+     * @description: 处理报警信息
+     * @author wangzl
+     * @date 2025/8/8
+     */
+    public BizDeviceAlarmPO handleAlarmData(BizInfusionHistoryPO infusionHistory, BizInfusionHistoryPO oldInfusionHistory, BizDeviceHistoryPO deviceHistory) {
+        //如果输入数据相同,则不处理
+        if(isEqual(infusionHistory, oldInfusionHistory)){
+            return null;
+        }
+        log.info("开始处理报警信息 新输注ID {}  ,设备ID {}", infusionHistory.getId(),  deviceHistory.getId());
+        BizDeviceAlarmPO alarmPO = BizDeviceAlarmMapper.INSTANCE.convertInfusionToPO(infusionHistory);
+        alarmPO.setDeviceType(deviceHistory.getDeviceType());
+        alarmPO.setDeviceId(deviceHistory.getId());
+        Function<BizInfusionHistoryPO, Boolean> check = o -> StrUtil.isNotBlank(o.getDeviceAlarm())
+                && !o.getDeviceAlarm().equals(FlowStatusEnum.None.name());
+        alarmPO.setAlarm(check.apply(infusionHistory));
+        log.info("报警信息处理完成 ");
+        return alarmPO;
+    }
+
+    /**
+     * @description: 校验输液历史记录是否相同
+     * @author wangzl
+     * @date 2025/8/8
+     */
+    public boolean isEqual(BizInfusionHistoryPO infusionHistory, BizInfusionHistoryPO oldInfusionHistory) {
+        if (infusionHistory == null && oldInfusionHistory == null) return true;
+        if (oldInfusionHistory == null || infusionHistory == null) return false;
+        List<BiFunction<BizInfusionHistoryPO, BizInfusionHistoryPO, Boolean>> checks = Arrays.asList(
+                (o, n) -> Objects.equals(o.getDeviceAlarm(), n.getDeviceAlarm()),
+                (o, n) -> Objects.equals(o.getWarnFlow(), n.getWarnFlow()),
+                (o, n) -> Objects.equals(o.getWarnAnalgesicPoor(), n.getWarnAnalgesicPoor()),
+                (o, n) -> Objects.equals(o.getWarnWillFinished(), n.getWarnWillFinished()),
+                (o, n) -> Objects.equals(o.getWarnLowBattery(), n.getWarnLowBattery())
+        );
+        return checks.stream().allMatch(check -> check.apply(oldInfusionHistory, infusionHistory));
+    }
+
+}

+ 32 - 3
tr-modules/tr-module-smartFollowUp/src/main/java/cn/tr/module/smart/common/config/RabbitMQConfig.java

@@ -10,23 +10,52 @@ import org.springframework.context.annotation.Configuration;
 
 @Configuration
 public class RabbitMQConfig {
-
+    /**
+     * 创建主题交换机
+     * @return TopicExchange 交换机实例
+     */
     @Bean
     public TopicExchange topicExchange() {
         // 设置交换机持久化
         return new TopicExchange(RabbitMQConstant.TOPIC_EXCHANGE_NAME, true, false);
     }
-
+    /**
+     * 创建镇痛泵数据接收队列
+     * @return Queue 队列实例
+     */
     @Bean
     public Queue patientMonitorQueue() {
         // 设置队列不持久化,并且在没有消费者时自动删除
         return new Queue(RabbitMQConstant.QUEUE_PATIENT_MONITOR, Boolean.FALSE, false, Boolean.TRUE);
     }
-
+    /**
+     * 绑定镇痛泵数据接收队列到主题交换机
+     * @return Binding 绑定实例
+     */
     @Bean
     public Binding patientMonitorBinding() {
         return BindingBuilder.bind(patientMonitorQueue())
                 .to(topicExchange())
                 .with(RabbitMQConstant.ROUTING_KEY_PATIENT_MONITOR);
     }
+
+    /**
+     * 创建服务号推送队列
+     * @return Queue 队列实例
+     */
+    @Bean
+    public Queue mpPushQueue() {
+        // 设置队列不持久化,并且在没有消费者时自动删除
+        return new Queue(RabbitMQConstant.QUEUE_MP_PUSH, Boolean.FALSE, false, Boolean.TRUE);
+    }
+    /**
+     * 绑定服务号推送队列到主题交换机
+     * @return Queue 队列实例
+     */
+    @Bean
+    public Binding mpPushBinding() {
+        return BindingBuilder.bind(patientMonitorQueue())
+                .to(topicExchange())
+                .with(RabbitMQConstant.ROUTING_KEY_MP_PUSH);
+    }
 }

+ 6 - 1
tr-modules/tr-module-smartFollowUp/src/main/java/cn/tr/module/smart/common/enums/RabbitMQConstant.java

@@ -2,10 +2,15 @@ package cn.tr.module.smart.common.enums;
 
 
 public interface RabbitMQConstant {
-    // 定义队列、交换机和路由键名称
+    // 网络泵定义队列、交换机和路由键名称
     String TOPIC_EXCHANGE_NAME = "nb.exchange";
 
     String ROUTING_KEY_PATIENT_MONITOR = "patient.monitor";
 
     String QUEUE_PATIENT_MONITOR = "patient.monitor.queue";
+
+
+    String ROUTING_KEY_MP_PUSH = "patient.mp.push";
+
+    String QUEUE_MP_PUSH = "patient.mp.push";
 }

+ 11 - 3
tr-modules/tr-module-smartFollowUp/src/main/java/cn/tr/module/smart/common/properties/ALiYunProperties.java

@@ -22,7 +22,15 @@ public class ALiYunProperties {
     private String aliAppKey;
     private String aliAppSecret;
 
-
-    private String bailianWorkplaceId;
-
+    /**
+     * 即时通讯的智能体
+     */
+    private Agent imAgent;
+
+    @Data
+    public static class Agent{
+        private String appId;
+        private String workplaceId;
+        private String apiKey;
+    }
 }

+ 2 - 1
tr-modules/tr-module-smartFollowUp/src/main/java/cn/tr/module/smart/common/service/impl/ALiYunServiceImpl.java

@@ -156,6 +156,7 @@ public class ALiYunServiceImpl implements ALiYunService {
      */
     @Override
     public String createMemory() throws Exception {
+        ALiYunProperties.Agent imAgent = aliyunProperties.getImAgent();
         Params params = new Params()
                 .setAction("CreateMemory")
                 .setVersion("2023-12-29")
@@ -163,7 +164,7 @@ public class ALiYunServiceImpl implements ALiYunService {
                 .setMethod("POST")
                 .setAuthType("AK")
                 .setStyle("ROA")
-                .setPathname("/" + com.aliyun.openapiutil.Client.getEncodeParam(aliyunProperties.getBailianWorkplaceId()) + "/memories")
+                .setPathname("/" + com.aliyun.openapiutil.Client.getEncodeParam(imAgent.getWorkplaceId()) + "/memories")
                 .setReqBodyType("json")
                 .setBodyType("json");
 

+ 4 - 3
tr-modules/tr-module-smartFollowUp/src/main/java/cn/tr/module/smart/common/service/impl/BizClinicRoomServiceImpl.java

@@ -490,10 +490,11 @@ public class BizClinicRoomServiceImpl implements IBizClinicRoomService {
     @Override
     @Transactional(rollbackFor = Exception.class)
     public BizAiAgentParamVO touchMemoryId(BizCreateAgentSessionDTO source) {
+        ALiYunProperties.Agent imAgent = aLiYunProperties.getImAgent();
         BizAiAgentParamVO result = new BizAiAgentParamVO();
-        result.setAppId(aLiYunProperties.getAppId());
-        result.setApiKey(aLiYunProperties.getApiKey());
-        result.setWorkspaceId(aLiYunProperties.getBailianWorkplaceId());
+        result.setAppId(imAgent.getAppId());
+        result.setApiKey(imAgent.getApiKey());
+        result.setWorkspaceId(imAgent.getWorkplaceId());
         BizClinicRoomPO clinicRoom = baseRepository.selectById(source.getClinicId());
         if (ObjectUtil.isNull(clinicRoom)) {
             throw new ServiceException(TRExcCode.SYSTEM_ERROR_B0001, "手术信息不存在");

+ 6 - 1
tr-test/src/main/resources/application-dev.yml

@@ -56,4 +56,9 @@ aliyun:
   llmModel: "qwen3-30b-a3b-instruct-2507"
   aliAppKey: "LTAI4G7FA9ytMc76oNkJ45YJ"
   aliAppSecret: "R7hOvMfiHb0PYroDqUDXAYgB9htQss"
-  bailianWorkplaceId: "llm-9othch7n7k4ue9uh"
+  bailianWorkplaceId: "llm-9othch7n7k4ue9uh"
+  imAgent:
+    workplaceId: "llm-9othch7n7k4ue9uh"
+    appId: "c71fc69490c0430186321c219fdd33dd"
+    apiKey: "sk-6038043b063c4f9eaadb497ec2fff50f"
+