ソースを参照

Merge branch 'han' of uskycloud/usky-modules into master

hanzhengyi 1 日 前
コミット
3dc81bd80c
26 ファイル変更1469 行追加145 行削除
  1. 63 0
      service-cdi/service-cdi-biz/src/main/java/com/usky/cdi/controller/AlarmDataController.java
  2. 6 5
      service-cdi/service-cdi-biz/src/main/java/com/usky/cdi/controller/BaseDataController.java
  3. 21 0
      service-cdi/service-cdi-biz/src/main/java/com/usky/cdi/controller/web/BaseBuildFacilityController.java
  4. 33 0
      service-cdi/service-cdi-biz/src/main/java/com/usky/cdi/controller/web/DmpDeviceInfoController.java
  5. 162 0
      service-cdi/service-cdi-biz/src/main/java/com/usky/cdi/domain/BaseBuildFacility.java
  6. 16 0
      service-cdi/service-cdi-biz/src/main/java/com/usky/cdi/mapper/BaseBuildFacilityMapper.java
  7. 18 0
      service-cdi/service-cdi-biz/src/main/java/com/usky/cdi/service/BaseBuildFacilityService.java
  8. 25 0
      service-cdi/service-cdi-biz/src/main/java/com/usky/cdi/service/DmpDeviceInfoService.java
  9. 0 41
      service-cdi/service-cdi-biz/src/main/java/com/usky/cdi/service/config/mqtt/MqttGateway.java
  10. 37 0
      service-cdi/service-cdi-biz/src/main/java/com/usky/cdi/service/config/mqtt/MqttOutConfig.java
  11. 187 0
      service-cdi/service-cdi-biz/src/main/java/com/usky/cdi/service/impl/AlarmDataTransferService.java
  12. 32 0
      service-cdi/service-cdi-biz/src/main/java/com/usky/cdi/service/impl/BaseBuildFacilityServiceImpl.java
  13. 124 44
      service-cdi/service-cdi-biz/src/main/java/com/usky/cdi/service/impl/BaseDataTransferService.java
  14. 35 0
      service-cdi/service-cdi-biz/src/main/java/com/usky/cdi/service/impl/DmpDeviceInfoServiceImpl.java
  15. 5 3
      service-cdi/service-cdi-biz/src/main/java/com/usky/cdi/service/impl/IotDataTransferService.java
  16. 115 38
      service-cdi/service-cdi-biz/src/main/java/com/usky/cdi/service/util/DeviceDataQuery.java
  17. 1 7
      service-cdi/service-cdi-biz/src/main/java/com/usky/cdi/service/util/DeviceDataSyncService.java
  18. 92 0
      service-cdi/service-cdi-biz/src/main/java/com/usky/cdi/service/util/WeatherFetcher.java
  19. 69 0
      service-cdi/service-cdi-biz/src/main/java/com/usky/cdi/service/vo/alarm/AlarmMessage1VO.java
  20. 69 0
      service-cdi/service-cdi-biz/src/main/java/com/usky/cdi/service/vo/alarm/AlarmMessage2VO.java
  21. 79 0
      service-cdi/service-cdi-biz/src/main/java/com/usky/cdi/service/vo/alarm/AlarmMessage3VO.java
  22. 74 0
      service-cdi/service-cdi-biz/src/main/java/com/usky/cdi/service/vo/alarm/AlarmMessageVO.java
  23. 161 0
      service-cdi/service-cdi-biz/src/main/java/com/usky/cdi/service/vo/base/FacilityDeviceVO.java
  24. 6 6
      service-cdi/service-cdi-biz/src/main/java/com/usky/cdi/service/vo/base/SensorInfoVO.java
  25. 38 0
      service-cdi/service-cdi-biz/src/main/resources/mapper/cdi/BaseBuildFacilityMapper.xml
  26. 1 1
      service-cdi/service-cdi-biz/src/main/resources/mapper/cdi/DmpDeviceMapper.xml

+ 63 - 0
service-cdi/service-cdi-biz/src/main/java/com/usky/cdi/controller/AlarmDataController.java

@@ -0,0 +1,63 @@
+package com.usky.cdi.controller;
+
+import com.usky.cdi.service.impl.AlarmDataTransferService;
+import com.usky.cdi.service.vo.alarm.AlarmMessage1VO;
+import com.usky.cdi.service.vo.alarm.AlarmMessage2VO;
+import com.usky.cdi.service.vo.alarm.AlarmMessage3VO;
+import com.usky.cdi.service.vo.alarm.AlarmMessageVO;
+import com.usky.cdi.service.vo.base.EngineeringBaseVO;
+import lombok.extern.slf4j.Slf4j;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
+import org.springframework.web.bind.annotation.PostMapping;
+import org.springframework.web.bind.annotation.RequestBody;
+import org.springframework.web.bind.annotation.RequestMapping;
+import org.springframework.web.bind.annotation.RestController;
+
+/**
+ * 基础类数据传输控制器
+ * 提供基础类数据上报的接口
+ *
+ * @author han
+ * @date 2025/12/08
+ */
+@Slf4j
+@RestController
+@RequestMapping("/api/alarm")
+@ConditionalOnProperty(prefix = "mqtt", value = {"enabled"}, havingValue = "true")
+public class AlarmDataController {
+    @Autowired
+    private AlarmDataTransferService alarmDataTransferService;
+    /**
+     * 上报人防工程基础信息
+     */
+    @PostMapping("/alarmMessage")
+    public String sendAlarmMessage(@RequestBody AlarmMessageVO vo) {
+        boolean success = alarmDataTransferService.sendAlarmMessage(vo);
+        return success ? "上报成功" : "上报失败";
+    }
+
+    /**
+     * 上报人防工程基础信息
+     */
+    @PostMapping("/alarmMessage1")
+    public String sendAlarmMessage1(@RequestBody AlarmMessage1VO vo) {
+        boolean success = alarmDataTransferService.sendAlarmMessage1(vo);
+        return success ? "上报成功" : "上报失败";
+    }
+
+    /**
+     * 上报倾斜、位移、裂缝监测事件
+     */
+    @PostMapping("/alarmMessage2")
+    public String sendAlarmMessage2(@RequestBody AlarmMessage2VO vo) {
+        boolean success = alarmDataTransferService.sendAlarmMessage2(vo);
+        return success ? "上报成功" : "上报失败";
+    }
+
+    @PostMapping("/alarmMessage3")
+    public String sendAlarmMessage3(@RequestBody AlarmMessage3VO vo) {
+        boolean success = alarmDataTransferService.sendEngineeringBase(vo);
+        return success ? "上报成功" : "上报失败";
+    }
+}

+ 6 - 5
service-cdi/service-cdi-biz/src/main/java/com/usky/cdi/controller/BaseDataController.java

@@ -1,5 +1,6 @@
 package com.usky.cdi.controller;
 
+import com.usky.cdi.domain.BaseBuildFacility;
 import com.usky.cdi.service.impl.BaseDataTransferService;
 import com.usky.cdi.service.vo.base.*;
 import lombok.extern.slf4j.Slf4j;
@@ -66,7 +67,7 @@ public class BaseDataController {
      * 上报智能监管物联设施信息
      */
     @PostMapping("/sensorInfo")
-    public String sendSensorInfo(@RequestBody SensorInfoVO vo) {
+    public String sendSensorInfo(@RequestBody FacilityDeviceVO vo) {
         boolean success = baseDataTransferService.sendSensorInfo(vo);
         return success ? "上报成功" : "上报失败";
     }
@@ -74,10 +75,10 @@ public class BaseDataController {
     /**
      * 批量上报智能监管物联设施信息
      */
-    @PostMapping("/sensorInfos")
-    public String batchSendSensorInfos(@RequestBody List<SensorInfoVO> sensors) {
-        int successCount = baseDataTransferService.batchSendSensorInfos(sensors);
-        return String.format("上报成功 %d/%d", successCount, sensors.size());
+    @GetMapping("/sensorInfos")
+    public String batchSendSensorInfos(@RequestParam(value = "tenantId",required = false) Integer tenantId) {
+        int successCount = baseDataTransferService.batchSendSensorInfos(tenantId);
+        return String.format("上报成功 %d", successCount);
     }
 }
 

+ 21 - 0
service-cdi/service-cdi-biz/src/main/java/com/usky/cdi/controller/web/BaseBuildFacilityController.java

@@ -0,0 +1,21 @@
+package com.usky.cdi.controller.web;
+
+
+import org.springframework.web.bind.annotation.RequestMapping;
+
+import org.springframework.stereotype.Controller;
+
+/**
+ * <p>
+ * 建筑设施 前端控制器
+ * </p>
+ *
+ * @author fu
+ * @since 2025-12-02
+ */
+@Controller
+@RequestMapping("/baseBuildFacility")
+public class BaseBuildFacilityController {
+
+}
+

+ 33 - 0
service-cdi/service-cdi-biz/src/main/java/com/usky/cdi/controller/web/DmpDeviceInfoController.java

@@ -0,0 +1,33 @@
+package com.usky.cdi.controller.web;
+
+import com.usky.backend.domain.*;
+import com.usky.cdi.domain.DmpDevice;
+import com.usky.cdi.service.DmpDeviceInfoService;
+import com.usky.common.core.bean.ApiResult;
+import com.usky.common.core.bean.CommonPage;
+import com.usky.common.core.utils.poi.ExcelUtil;
+import io.swagger.annotations.ApiOperation;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.web.bind.annotation.*;
+import org.springframework.web.multipart.MultipartFile;
+
+import javax.servlet.http.HttpServletResponse;
+import java.io.IOException;
+import java.util.List;
+import java.util.Map;
+
+/**
+ * 设备信息表
+ *
+ * @author ya
+ * @since 2022-10-08
+ */
+@RestController
+@RequestMapping("/dmpDeviceInfo")
+public class DmpDeviceInfoController {
+
+    @Autowired
+    private DmpDeviceInfoService dmpDeviceInfoService;
+
+}
+

+ 162 - 0
service-cdi/service-cdi-biz/src/main/java/com/usky/cdi/domain/BaseBuildFacility.java

@@ -0,0 +1,162 @@
+package com.usky.cdi.domain;
+
+import com.baomidou.mybatisplus.annotation.IdType;
+import com.baomidou.mybatisplus.annotation.TableId;
+import java.time.LocalDateTime;
+import java.io.Serializable;
+import lombok.Data;
+import lombok.EqualsAndHashCode;
+
+/**
+ * <p>
+ * 建筑设施
+ * </p>
+ *
+ * @author fu
+ * @since 2025-12-02
+ */
+@Data
+@EqualsAndHashCode(callSuper = false)
+public class BaseBuildFacility implements Serializable {
+
+    private static final long serialVersionUID = 1L;
+
+    /**
+     * 主键
+     */
+    @TableId(value = "id", type = IdType.AUTO)
+    private Integer id;
+
+    /**
+     * 设施编号
+     */
+    private String facilityNum;
+
+    /**
+     * 设施名称
+     */
+    private String facilityName;
+
+    /**
+     * 设施类型
+     */
+    private String facilityType;
+
+    /**
+     * 所属楼层
+     */
+    private String floor;
+
+    /**
+     * 安装位置
+     */
+    private String address;
+
+    /**
+     * 图⽚地址URL
+     */
+    private String imagesUrl;
+
+    /**
+     * 设备ID
+     */
+    private String deviceId;
+
+    /**
+     * 联系人
+     */
+    private String contact;
+
+    /**
+     * 联系方式
+     */
+    private String contactPhone;
+
+    /**
+     * 平面X轴坐标
+     */
+    private String planeX;
+
+    /**
+     * 平面Y轴坐标
+     */
+    private String planeY;
+
+    private String coordinateX;
+
+    private String coordinateY;
+
+    private String coordinateZ;
+
+    /**
+     * 删除标识
+     */
+    private Integer deleteFlag;
+
+    /**
+     * 创建时间
+     */
+    private LocalDateTime createTime;
+
+    /**
+     * 更新时间
+     */
+    private LocalDateTime updateTime;
+
+    /**
+     * 更新人
+     */
+    private String updateBy;
+
+    /**
+     * 创建人
+     */
+    private String createBy;
+
+    /**
+     * 组织结构ID
+     */
+    private Integer deptId;
+
+    /**
+     * 租户ID
+     */
+    private Integer tenantId;
+
+    /**
+     * 建筑设施备注
+     */
+    private String facilityDesc;
+
+    /**
+     * 三维角度X
+     */
+    private Double anglesX;
+
+    /**
+     * 三维角度y
+     */
+    private Double anglesY;
+
+    /**
+     * 三维角度z
+     */
+    private Double anglesZ;
+
+    /**
+     * 三维图标大小
+     */
+    private Double scaleL;
+
+    /**
+     * 三维图标大小
+     */
+    private Double scaleW;
+
+    /**
+     * 三维图标大小
+     */
+    private Double scaleH;
+
+
+}

+ 16 - 0
service-cdi/service-cdi-biz/src/main/java/com/usky/cdi/mapper/BaseBuildFacilityMapper.java

@@ -0,0 +1,16 @@
+package com.usky.cdi.mapper;
+
+import com.usky.cdi.domain.BaseBuildFacility;
+import com.usky.common.mybatis.core.CrudMapper;
+
+/**
+ * <p>
+ * 建筑设施 Mapper 接口
+ * </p>
+ *
+ * @author fu
+ * @since 2025-12-02
+ */
+public interface BaseBuildFacilityMapper extends CrudMapper<BaseBuildFacility> {
+
+}

+ 18 - 0
service-cdi/service-cdi-biz/src/main/java/com/usky/cdi/service/BaseBuildFacilityService.java

@@ -0,0 +1,18 @@
+package com.usky.cdi.service;
+
+import com.usky.cdi.domain.BaseBuildFacility;
+import com.usky.common.mybatis.core.CrudService;
+
+import java.util.List;
+
+/**
+ * <p>
+ * 建筑设施 服务类
+ * </p>
+ *
+ * @author fu
+ * @since 2025-12-02
+ */
+public interface BaseBuildFacilityService extends CrudService<BaseBuildFacility> {
+    List<BaseBuildFacility> facilityInfo(Integer tenantId);
+}

+ 25 - 0
service-cdi/service-cdi-biz/src/main/java/com/usky/cdi/service/DmpDeviceInfoService.java

@@ -0,0 +1,25 @@
+package com.usky.cdi.service;
+
+import com.usky.backend.domain.*;
+import com.usky.cdi.domain.BaseBuildFacility;
+import com.usky.cdi.domain.DmpDevice;
+import com.usky.common.core.bean.CommonPage;
+import com.usky.common.mybatis.core.CrudService;
+import org.springframework.web.multipart.MultipartFile;
+
+import javax.servlet.http.HttpServletResponse;
+import java.util.List;
+import java.util.Map;
+
+
+/**
+ * <p>
+ * 设备信息表
+ * </p>
+ *
+ * @author ya
+ * @since 2022-10-08
+ */
+public interface DmpDeviceInfoService extends CrudService<DmpDevice> {
+    List<DmpDevice> deviceInfo(Integer tenantId);
+}

+ 0 - 41
service-cdi/service-cdi-biz/src/main/java/com/usky/cdi/service/config/mqtt/MqttGateway.java

@@ -1,41 +0,0 @@
-package com.usky.cdi.service.config.mqtt;
-
-import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
-import org.springframework.integration.annotation.MessagingGateway;
-import org.springframework.integration.mqtt.support.MqttHeaders;
-import org.springframework.messaging.handler.annotation.Header;
-
-/**
- * MQTT消息发送网关
- * 
- * @author han
- * @date 2025/03/20
- */
-@ConditionalOnProperty(prefix = "mqtt", value = {"enabled"}, havingValue = "true")
-@MessagingGateway(defaultRequestChannel = MqttOutConfig.CHANNEL_NAME_OUT)
-public interface MqttGateway {
-    /**
-     * 发送消息
-     *
-     * @param payload 消息内容
-     */
-    void sendToMqtt(String payload);
-
-    /**
-     * 指定topic发送消息
-     *
-     * @param topic 消息主题
-     * @param payload 消息内容
-     */
-    void sendToMqtt(@Header(MqttHeaders.TOPIC) String topic, String payload);
-
-    /**
-     * 指定topic和qos发送消息
-     *
-     * @param topic 消息主题
-     * @param qos 消息质量等级
-     * @param payload 消息内容
-     */
-    void sendToMqtt(@Header(MqttHeaders.TOPIC) String topic, @Header(MqttHeaders.QOS) int qos, String payload);
-}
-

+ 37 - 0
service-cdi/service-cdi-biz/src/main/java/com/usky/cdi/service/config/mqtt/MqttOutConfig.java

@@ -1,5 +1,6 @@
 package com.usky.cdi.service.config.mqtt;
 
+import com.alibaba.fastjson.JSONObject;
 import org.springframework.beans.factory.annotation.Autowired;
 import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
 import org.springframework.context.annotation.Bean;
@@ -13,6 +14,8 @@ import org.springframework.messaging.MessageChannel;
 import org.springframework.messaging.MessageHandler;
 import org.springframework.messaging.handler.annotation.Header;
 
+import java.util.Map;
+
 /**
  * @author han
  * @date 2025/03/20 14:31
@@ -57,4 +60,38 @@ public class MqttOutConfig {
         return messageHandler;
     }
 
+    @MessagingGateway(defaultRequestChannel = CHANNEL_NAME_OUT)
+    public interface MqttGateway {
+        /**
+         * 发送消息
+         *
+         * @param payload
+         */
+        void sendToMqtt(String payload);
+
+        /**
+         * 指定top发送消息
+         *
+         * @param topic
+         * @param payload
+         */
+        void sendToMqtt(@Header(MqttHeaders.TOPIC) String topic, String payload);
+
+        /**
+         * 指定top发送消息
+         *
+         * @param topic
+         * @param payload
+         */
+        void sendToMqtt(@Header(MqttHeaders.TOPIC) String topic, Map<String, Object> payload);
+
+        /**
+         * 指定队列和qos
+         *
+         * @param topic
+         * @param qos
+         * @param payload
+         */
+        void sendToMqtt(@Header(MqttHeaders.TOPIC) String topic, @Header(MqttHeaders.QOS) int qos, String payload);
+    }
 }

+ 187 - 0
service-cdi/service-cdi-biz/src/main/java/com/usky/cdi/service/impl/AlarmDataTransferService.java

@@ -0,0 +1,187 @@
+package com.usky.cdi.service.impl;
+
+import com.alibaba.fastjson.JSON;
+import com.alibaba.fastjson.JSONObject;
+import com.alibaba.nacos.shaded.com.google.gson.Gson;
+import com.usky.cdi.service.config.mqtt.MqttOutConfig;
+import com.usky.cdi.service.util.SnowflakeIdGenerator;
+import com.usky.cdi.service.vo.alarm.AlarmMessage1VO;
+import com.usky.cdi.service.vo.alarm.AlarmMessage2VO;
+import com.usky.cdi.service.vo.alarm.AlarmMessage3VO;
+import com.usky.cdi.service.vo.alarm.AlarmMessageVO;
+import com.usky.cdi.service.vo.base.EngineeringBaseVO;
+import com.usky.cdi.service.vo.base.FloorPlaneVO;
+import lombok.extern.slf4j.Slf4j;
+import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
+import org.springframework.stereotype.Service;
+
+import javax.annotation.Resource;
+import java.nio.file.Files;
+import java.nio.file.Paths;
+import java.text.SimpleDateFormat;
+import java.util.Date;
+import java.util.HashMap;
+
+/**
+ * 告警类数据传输服务
+ * 负责向市适配平台发送告警类数据
+ *
+ * @author han
+ * @date 2025/12/08
+ */
+@Slf4j
+@Service
+@ConditionalOnProperty(prefix = "mqtt", value = {"enabled"}, havingValue = "true")
+public class AlarmDataTransferService {
+
+    @Resource
+    private MqttOutConfig.MqttGateway mqttGateway;
+
+    private final SnowflakeIdGenerator idGenerator;
+    private final SimpleDateFormat timeFormat = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss.SSS");
+
+    public AlarmDataTransferService() {
+        // 使用默认的workerId和datacenterId,实际项目中可以从配置读取
+        this.idGenerator = new SnowflakeIdGenerator(1L, 1L);
+    }
+
+    /**
+     * 获取当前时间字符串
+     */
+    private String getCurrentTime() {
+        return timeFormat.format(new Date());
+    }
+
+    /**
+     * 生成数据包ID
+     */
+    private Long generateDataPacketID() {
+        return idGenerator.nextPacketId();
+    }
+
+    /**
+     * 发送告警信息
+     * Topic: base/floorPlane
+     *
+     * @param vo 楼层平面图信息
+     * @return 是否发送成功
+     */
+    public boolean sendAlarmMessage(AlarmMessageVO vo) {
+        try {
+            if (vo.getDataPacketID() == null) {
+                vo.setDataPacketID(generateDataPacketID());
+            }
+            if (vo.getPublishTime() == null) {
+                vo.setPublishTime(getCurrentTime());
+            }
+
+            HashMap<String, Object> map = new HashMap<>();
+//            map.put("dataPacketID", vo.getDataPacketID());
+//            map.put("engineeringID", vo.getEngineeringID());
+//            map.put("floor", vo.getFloor());
+//            map.put("floorFileID", vo.getFloorFileID());
+//            map.put("floorFileName", vo.getFloorFileName());
+//            map.put("floorFileSuffix", vo.getFloorFileSuffix());
+//            map.put("filePixWidth", vo.getFilePixWidth());
+//            map.put("filePixHeight", vo.getFilePixHeight());
+//            map.put("floorFile", imageBytes);
+//            map.put("publishTime", vo.getPublishTime());
+            Gson gson = new Gson();
+            JSONObject jsonObject = (JSONObject) JSON.toJSON(vo);
+            String json = jsonObject.toJSONString();
+            System.out.println(json);
+            String topic = "alarm/message";
+            mqttGateway.sendToMqtt(topic, json);
+
+            return true;
+        } catch (Exception e) {
+            log.error("发送告警信息失败,AlarmID: {}", vo.getAlarmID(), e);
+            return false;
+        }
+    }
+
+    /**
+     * 发送告警信息
+     * Topic: base/floorPlane
+     *
+     * @param vo 楼层平面图信息
+     * @return 是否发送成功
+     */
+    public boolean sendAlarmMessage1(AlarmMessage1VO vo) {
+        try {
+            if (vo.getDataPacketID() == null) {
+                vo.setDataPacketID(generateDataPacketID());
+            }
+            if (vo.getPublishTime() == null) {
+                vo.setPublishTime(getCurrentTime());
+            }
+
+            HashMap<String, Object> map = new HashMap<>();
+//            map.put("dataPacketID", vo.getDataPacketID());
+//            map.put("engineeringID", vo.getEngineeringID());
+//            map.put("floor", vo.getFloor());
+//            map.put("floorFileID", vo.getFloorFileID());
+//            map.put("floorFileName", vo.getFloorFileName());
+//            map.put("floorFileSuffix", vo.getFloorFileSuffix());
+//            map.put("filePixWidth", vo.getFilePixWidth());
+//            map.put("filePixHeight", vo.getFilePixHeight());
+//            map.put("floorFile", imageBytes);
+//            map.put("publishTime", vo.getPublishTime());
+            Gson gson = new Gson();
+            JSONObject jsonObject = (JSONObject) JSON.toJSON(vo);
+            String json = jsonObject.toJSONString();
+            System.out.println(json);
+            String topic = "alarm/message";
+            mqttGateway.sendToMqtt(topic, json);
+
+            return true;
+        } catch (Exception e) {
+            log.error("发送告警信息失败,AlarmID: {}", vo.getAlarmID(), e);
+            return false;
+        }
+    }
+
+    public boolean sendAlarmMessage2(AlarmMessage2VO vo) {
+        try {
+            if (vo.getDataPacketID() == null) {
+                vo.setDataPacketID(generateDataPacketID());
+            }
+            if (vo.getPublishTime() == null) {
+                vo.setPublishTime(getCurrentTime());
+            }
+
+            JSONObject jsonObject = (JSONObject) JSON.toJSON(vo);
+            String json = jsonObject.toJSONString();
+            System.out.println(json);
+            String topic = "alarm/message";
+            mqttGateway.sendToMqtt(topic, json);
+
+            return true;
+        } catch (Exception e) {
+            log.error("发送告警信息失败,AlarmID: {}", vo.getAlarmID(), e);
+            return false;
+        }
+    }
+
+    public boolean sendEngineeringBase(AlarmMessage3VO vo) {
+        try {
+            if (vo.getDataPacketID() == null) {
+                vo.setDataPacketID(generateDataPacketID());
+            }
+            if (vo.getPublishTime() == null) {
+                vo.setPublishTime(getCurrentTime());
+            }
+
+            JSONObject jsonObject = (JSONObject) JSON.toJSON(vo);
+            String json = jsonObject.toJSONString();
+            String topic = "alarm/message";
+            System.out.println("推送的数据: " + json);
+            mqttGateway.sendToMqtt(topic, json);
+
+            return true;
+        } catch (Exception e) {
+            log.error("发送电流告警信息失败,EngineeringID: {}", vo.getEngineeringID(), e);
+            return false;
+        }
+    }
+}

+ 32 - 0
service-cdi/service-cdi-biz/src/main/java/com/usky/cdi/service/impl/BaseBuildFacilityServiceImpl.java

@@ -0,0 +1,32 @@
+package com.usky.cdi.service.impl;
+
+import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
+import com.baomidou.mybatisplus.core.toolkit.Wrappers;
+import com.usky.cdi.domain.BaseBuildFacility;
+import com.usky.cdi.mapper.BaseBuildFacilityMapper;
+import com.usky.cdi.service.BaseBuildFacilityService;
+import com.usky.common.mybatis.core.AbstractCrudService;
+import com.usky.common.security.utils.SecurityUtils;
+import org.springframework.stereotype.Service;
+
+import java.util.List;
+
+/**
+ * <p>
+ * 建筑设施 服务实现类
+ * </p>
+ *
+ * @author fu
+ * @since 2025-12-02
+ */
+@Service
+public class BaseBuildFacilityServiceImpl extends AbstractCrudService<BaseBuildFacilityMapper, BaseBuildFacility> implements BaseBuildFacilityService {
+    @Override
+    public List<BaseBuildFacility> facilityInfo(Integer tenantId){
+        LambdaQueryWrapper<BaseBuildFacility> queryWrapper = Wrappers.lambdaQuery();
+        queryWrapper.eq(BaseBuildFacility::getDeleteFlag,0)
+                .eq(BaseBuildFacility::getTenantId, tenantId);
+        List<BaseBuildFacility> list = this.list(queryWrapper);
+        return list;
+    }
+}

+ 124 - 44
service-cdi/service-cdi-biz/src/main/java/com/usky/cdi/service/impl/BaseDataTransferService.java

@@ -2,16 +2,26 @@ package com.usky.cdi.service.impl;
 
 import com.alibaba.fastjson.JSON;
 import com.alibaba.fastjson.JSONObject;
-import com.usky.cdi.service.config.mqtt.MqttGateway;
+import com.alibaba.nacos.shaded.com.google.gson.Gson;
+import com.baomidou.mybatisplus.core.toolkit.CollectionUtils;
+import com.usky.cdi.domain.BaseBuildFacility;
+import com.usky.cdi.domain.DmpDevice;
+import com.usky.cdi.service.BaseBuildFacilityService;
+import com.usky.cdi.service.DmpDeviceInfoService;
+import com.usky.cdi.service.config.mqtt.MqttOutConfig;
 import com.usky.cdi.service.util.SnowflakeIdGenerator;
 import com.usky.cdi.service.vo.base.*;
 import lombok.extern.slf4j.Slf4j;
 import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.beans.factory.annotation.Value;
 import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
 import org.springframework.stereotype.Service;
 
+import javax.annotation.Resource;
+import java.nio.file.Files;
+import java.nio.file.Paths;
 import java.text.SimpleDateFormat;
-import java.util.Date;
+import java.util.*;
 
 /**
  * 基础类数据传输服务
@@ -25,8 +35,17 @@ import java.util.Date;
 @ConditionalOnProperty(prefix = "mqtt", value = {"enabled"}, havingValue = "true")
 public class BaseDataTransferService {
 
-    @Autowired(required = false)
-    private MqttGateway mqttGateway;
+    @Autowired
+    private BaseBuildFacilityService baseBuildFacilityService;
+
+    @Autowired
+    private DmpDeviceInfoService dmpDeviceInfoService;
+
+    @Resource
+    private MqttOutConfig.MqttGateway mqttGateway;
+
+    @Value("${config.engineeringID}")
+    private String engineeringID;
 
     private final SnowflakeIdGenerator idGenerator;
     private final SimpleDateFormat timeFormat = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss.SSS");
@@ -58,10 +77,6 @@ public class BaseDataTransferService {
      * @return 是否发送成功
      */
     public boolean sendEngineeringBase(EngineeringBaseVO vo) {
-        if (mqttGateway == null) {
-            log.warn("MQTT Gateway未初始化,无法发送消息");
-            return false;
-        }
         try {
             if (vo.getDataPacketID() == null) {
                 vo.setDataPacketID(generateDataPacketID());
@@ -91,10 +106,6 @@ public class BaseDataTransferService {
      * @return 是否发送成功
      */
     public boolean sendProtectiveUnit(ProtectiveUnitVO vo) {
-        if (mqttGateway == null) {
-            log.warn("MQTT Gateway未初始化,无法发送消息");
-            return false;
-        }
         try {
             if (vo.getDataPacketID() == null) {
                 vo.setDataPacketID(generateDataPacketID());
@@ -124,10 +135,6 @@ public class BaseDataTransferService {
      * @return 是否发送成功
      */
     public boolean sendFloorPlane(FloorPlaneVO vo) {
-        if (mqttGateway == null) {
-            log.warn("MQTT Gateway未初始化,无法发送消息");
-            return false;
-        }
         try {
             if (vo.getDataPacketID() == null) {
                 vo.setDataPacketID(generateDataPacketID());
@@ -136,27 +143,46 @@ public class BaseDataTransferService {
                 vo.setPublishTime(getCurrentTime());
             }
 
+            String imagePath = "D://games/3492.jpg";
+            // 将图片文件读取为字节数组
+            byte[] imageBytes = Files.readAllBytes(Paths.get(imagePath));
+
             // 检查文件大小(不超过5MB)
-            if (vo.getFloorFile() != null && vo.getFloorFile().length > 5 * 1024 * 1024) {
+            if (vo.getFloorFile() != null && imageBytes.length > 5 * 1024 * 1024) {
                 log.error("楼层平面图文件大小超过5MB限制,FileID: {}", vo.getFloorFileID());
                 return false;
             }
 
+            HashMap<String, Object> map = new HashMap<>();
+            map.put("dataPacketID", vo.getDataPacketID());
+            map.put("engineeringID", vo.getEngineeringID());
+            map.put("floor", vo.getFloor());
+            map.put("floorFileID", vo.getFloorFileID());
+            map.put("floorFileName", vo.getFloorFileName());
+            map.put("floorFileSuffix", vo.getFloorFileSuffix());
+            map.put("filePixWidth", vo.getFilePixWidth());
+            map.put("filePixHeight", vo.getFilePixHeight());
+            map.put("floorFile", imageBytes);
+            map.put("publishTime", vo.getPublishTime());
+            Gson gson = new Gson();
             // 将字节数组转换为Base64编码
             JSONObject jsonObject = (JSONObject) JSON.toJSON(vo);
+            vo.setFloorFile(imageBytes);
+//            jsonObject.put("floorFile", imageBytes);
             if (vo.getFloorFile() != null) {
                 // 使用Base64编码传输二进制数据
                 String base64File = java.util.Base64.getEncoder().encodeToString(vo.getFloorFile());
-                jsonObject.put("floorFile", base64File);
+                jsonObject.put("floorFile", imageBytes);
             }
 
             String json = jsonObject.toJSONString();
+            System.out.println(gson.toJson(map));
             String topic = "base/floorPlane";
             
             log.info("发送楼层平面图信息,Topic: {}, FileID: {}, FileSize: {} bytes", 
                     topic, vo.getFloorFileID(), 
                     vo.getFloorFile() != null ? vo.getFloorFile().length : 0);
-            mqttGateway.sendToMqtt(topic, json);
+            mqttGateway.sendToMqtt(topic, gson.toJson(map));
             
             return true;
         } catch (Exception e) {
@@ -165,6 +191,21 @@ public class BaseDataTransferService {
         }
     }
 
+    /**
+     * 根据输入的键(key)从Map中匹配并返回对应的值
+     * @param key 要匹配的键(输入值)
+     * @param dataMap 存储键值对的Map
+     * @return 匹配到的值(若未匹配到返回null)
+     */
+    public static <K, V> V matchByKey(K key, Map<K, V> dataMap) {
+        // 判空处理(避免空指针)
+        if (key == null || dataMap == null) {
+            return null;
+        }
+        // 直接通过Map的get方法匹配
+        return dataMap.get(key);
+    }
+
     /**
      * 发送智能监管物联设施信息
      * Topic: base/sensorInfo
@@ -172,24 +213,43 @@ public class BaseDataTransferService {
      * @param vo 智能监管物联设施信息
      * @return 是否发送成功
      */
-    public boolean sendSensorInfo(SensorInfoVO vo) {
-        if (mqttGateway == null) {
-            log.warn("MQTT Gateway未初始化,无法发送消息");
-            return false;
-        }
+    public boolean sendSensorInfo(FacilityDeviceVO vo) {
         try {
-            if (vo.getDataPacketID() == null) {
-                vo.setDataPacketID(generateDataPacketID());
-            }
-            if (vo.getPublishTime() == null) {
-                vo.setPublishTime(getCurrentTime());
-            }
+            Map<Integer, Integer> userIdToName = new HashMap<>();
+            userIdToName.put(702, 31);
+            userIdToName.put(703, 33);
+            userIdToName.put(704, 11);
+            userIdToName.put(707, 19);
+            userIdToName.put(708, 19);
+            userIdToName.put(709, 15);
+            userIdToName.put(710, 16);
+            userIdToName.put(711, 2);
+            userIdToName.put(712, 34);
+            userIdToName.put(713, 36);
+            userIdToName.put(714, 37);
 
-            String json = JSON.toJSONString(vo);
+            HashMap<String, Object> map = new HashMap<>();
+            map.put("dataPacketID", generateDataPacketID());
+            map.put("engineeringID", Long.parseLong(engineeringID));
+            map.put("floor", "B2");
+            map.put("floorFileID", 1);
+            map.put("sensorID", Integer.parseInt(vo.getDeviceId()));
+            map.put("sensorNo", vo.getDeviceUuid());
+            map.put("sensorType", matchByKey(vo.getDeviceType(), userIdToName));
+            map.put("unitName", vo.getFacilityDesc());
+            map.put("monitorObjNo", vo.getFacilityNum());
+            map.put("monitorObj", vo.getFacilityName());
+            map.put("location", vo.getAddress());
+//            map.put("xCoordinate", (int) Math.floor(Double.parseDouble(vo.getPlaneX())*4.34));
+//            map.put("yCoordinate", (int) Math.floor(Double.parseDouble(vo.getPlaneY())*4.34));
+            map.put("xCoordinate", Integer.valueOf(vo.getPlaneX()));
+            map.put("yCoordinate", Integer.valueOf(vo.getPlaneY()));
+            map.put("publishTime", getCurrentTime());
+            Gson gson = new Gson();
             String topic = "base/sensorInfo";
-            
-            log.info("发送智能监管物联设施信息,Topic: {}, SensorID: {}", topic, vo.getSensorID());
-            mqttGateway.sendToMqtt(topic, json);
+            System.out.println(gson.toJson(map));
+//            log.info("发送智能监管物联设施信息,Topic: {}, SensorID: {}", topic, vo.getSensorID());
+            mqttGateway.sendToMqtt(topic, gson.toJson(map));
             
             return true;
         } catch (Exception e) {
@@ -223,22 +283,42 @@ public class BaseDataTransferService {
     /**
      * 批量发送智能监管物联设施信息
      * 
-     * @param sensors 物联设施列表
+     * @param tenantId 租户ID
      * @return 成功发送的数量
      */
-    public int batchSendSensorInfos(java.util.List<SensorInfoVO> sensors) {
-        if (sensors == null || sensors.isEmpty()) {
-            return 0;
+    public int batchSendSensorInfos(Integer tenantId) {
+        List<BaseBuildFacility> list = baseBuildFacilityService.facilityInfo(tenantId);
+        List<DmpDevice> list1 = dmpDeviceInfoService.deviceInfo(tenantId);
+        List<FacilityDeviceVO> list2 = new ArrayList<>();
+        if(CollectionUtils.isNotEmpty(list)&&CollectionUtils.isNotEmpty(list1)){
+            for (int j=0;j<list.size();j++) {
+                for (int k=0;k<list1.size();k++) {
+                    if (list.get(j).getDeviceId().equals(list1.get(k).getDeviceId())){
+                        FacilityDeviceVO facilityDeviceVO = new FacilityDeviceVO();
+                        facilityDeviceVO.setFloor(list.get(j).getFloor());
+                        facilityDeviceVO.setFacilityName(list.get(j).getFacilityName());
+                        facilityDeviceVO.setFacilityNum(list.get(j).getFacilityNum());
+                        facilityDeviceVO.setDeviceId(list.get(j).getDeviceId());
+                        facilityDeviceVO.setAddress(list.get(j).getAddress());
+                        facilityDeviceVO.setPlaneX(list.get(j).getPlaneX());
+                        facilityDeviceVO.setPlaneY(list.get(j).getPlaneY());
+                        facilityDeviceVO.setDeviceUuid(list1.get(k).getDeviceUuid());
+                        facilityDeviceVO.setFacilityDesc(list.get(j).getFacilityDesc());
+                        facilityDeviceVO.setDeviceType(list1.get(k).getDeviceType());
+                        list2.add(facilityDeviceVO);
+                    }
+                }
+            }
         }
-        
         int successCount = 0;
-        for (SensorInfoVO sensor : sensors) {
-            if (sendSensorInfo(sensor)) {
-                successCount++;
+        if(CollectionUtils.isNotEmpty(list2)){
+            for (int i=0;i<list2.size();i++) {
+                if (sendSensorInfo(list2.get(i))) {
+                    successCount++;
+                }
             }
         }
-        
-        log.info("批量发送智能监管物联设施信息,总数: {}, 成功: {}", sensors.size(), successCount);
+        log.info("批量发送智能监管物联设施信息,总数: {}, 成功: {}", list2.size(), successCount);
         return successCount;
     }
 }

+ 35 - 0
service-cdi/service-cdi-biz/src/main/java/com/usky/cdi/service/impl/DmpDeviceInfoServiceImpl.java

@@ -0,0 +1,35 @@
+package com.usky.cdi.service.impl;
+
+
+import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
+import com.baomidou.mybatisplus.core.toolkit.Wrappers;
+import com.usky.cdi.domain.BaseBuildFacility;
+import com.usky.cdi.domain.DmpDevice;
+import com.usky.cdi.mapper.DmpDeviceMapper;
+import com.usky.cdi.service.DmpDeviceInfoService;
+import com.usky.common.mybatis.core.AbstractCrudService;
+import lombok.extern.slf4j.Slf4j;
+import org.springframework.stereotype.Service;
+
+import java.util.List;
+
+/**
+ * <p>
+ * 设备信息表 服务实现类
+ * </p>
+ *
+ * @author ya
+ * @since 2022-10-08
+ */
+@Slf4j
+@Service
+public class DmpDeviceInfoServiceImpl extends AbstractCrudService<DmpDeviceMapper, DmpDevice> implements DmpDeviceInfoService {
+    @Override
+    public List<DmpDevice> deviceInfo(Integer tenantId){
+        LambdaQueryWrapper<DmpDevice> queryWrapper = Wrappers.lambdaQuery();
+        queryWrapper.eq(DmpDevice::getDeleteFlag,0)
+                .eq(DmpDevice::getTenantId, tenantId);
+        List<DmpDevice> list = this.list(queryWrapper);
+        return list;
+    }
+}

+ 5 - 3
service-cdi/service-cdi-biz/src/main/java/com/usky/cdi/service/impl/IotDataTransferService.java

@@ -7,7 +7,8 @@ import com.usky.cdi.domain.DmpDevice;
 import com.usky.cdi.domain.DmpProduct;
 import com.usky.cdi.mapper.DmpDeviceMapper;
 import com.usky.cdi.mapper.DmpProductMapper;
-import com.usky.cdi.service.config.mqtt.MqttGateway;
+//import com.usky.cdi.service.config.mqtt.MqttGateway;
+import com.usky.cdi.service.config.mqtt.MqttOutConfig;
 import com.usky.cdi.service.enums.EnvMonitorMqttTopic;
 import com.usky.cdi.service.util.DeviceDataQuery;
 import com.usky.cdi.service.util.SnowflakeIdGenerator;
@@ -21,6 +22,7 @@ import org.springframework.stereotype.Service;
 
 import javax.annotation.PostConstruct;
 
+import javax.annotation.Resource;
 import java.time.Instant;
 import java.time.LocalDateTime;
 import java.time.ZoneId;
@@ -40,8 +42,8 @@ import java.util.stream.Collectors;
 @ConditionalOnProperty(prefix = "mqtt", value = {"enabled"}, havingValue = "true")
 public class IotDataTransferService {
 
-    @Autowired(required = false)
-    private MqttGateway mqttGateway;
+    @Resource
+    private MqttOutConfig.MqttGateway mqttGateway;
 
     private SnowflakeIdGenerator idGenerator;
 

+ 115 - 38
service-cdi/service-cdi-biz/src/main/java/com/usky/cdi/service/util/DeviceDataQuery.java

@@ -15,6 +15,7 @@ import org.springframework.stereotype.Component;
 
 import java.text.DecimalFormat;
 import java.util.*;
+import java.util.concurrent.ConcurrentHashMap;
 import java.util.concurrent.ThreadLocalRandom;
 import java.util.stream.Collectors;
 
@@ -43,6 +44,42 @@ public class DeviceDataQuery {
     private static final DecimalFormat FORMAT_3_2 = new DecimalFormat("000.00"); // 3位整数+2位小数
     private static final DecimalFormat FORMAT_4_2 = new DecimalFormat("0000.00"); // 4位整数+2位小数
 
+    // ========== 新增缓存相关成员变量 ==========
+    // 缓存A/B/C相电流值
+    private static final Map<String, Double> currentValueCache = new ConcurrentHashMap<>();
+    // 缓存各相复用次数
+    private static final Map<String, Integer> currentReuseCountCache = new ConcurrentHashMap<>();
+    // 最大复用次数(可调整)
+    private static final int MAX_REUSE_COUNT = 3;
+    // 复用概率(0.5=50%概率复用,可调整)
+    private static final double REUSE_PROBABILITY = 0.5;
+
+    // 定义模拟数据范围常量
+    private static final double TEMP_RANGE_MIN = 10.0;
+    private static final double TEMP_RANGE_MAX = 20.0;
+    private static final double HUMIDITY_RANGE_MIN = 40.0;
+    private static final double HUMIDITY_RANGE_MAX = 41.0;
+    private static final double OXYGEN_RANGE_MIN = 20.0;
+    private static final double OXYGEN_RANGE_MAX = 21.0;
+    private static final double CO2_RANGE_MIN = 480.0;
+    private static final double CO2_RANGE_MAX = 490.0;
+    private static final double VOLTAGE_RANGE_MIN = 220.0;
+    private static final double VOLTAGE_RANGE_MAX = 230.0;
+    private static final double CURRENT_RANGE_MIN = 0.0;
+    private static final double CURRENT_RANGE_MAX = 1.5;
+    private static final double POWER_RANGE_MIN = 1.0;
+    private static final double POWER_RANGE_MAX = 20.0;
+    private static final double TEMP_LINE_RANGE_MIN = 20.0;
+    private static final double TEMP_LINE_RANGE_MAX = 50.0;
+    private static final double LEAKAGE_CURRENT_RANGE_MIN = 50.0;
+    private static final double LEAKAGE_CURRENT_RANGE_MAX = 60.0;
+    private static final double FLOATING_RANGE_MIN = 0.0;
+    private static final double FLOATING_RANGE_MAX = 0.5;
+    private static final double FLOATING_RANGE_MIN1 = 0.0;
+    private static final double FLOATING_RANGE_MAX1 = 1.0;
+
+    private static int callCount = 0;
+
     /**
      * 获取指定设备类型的设备数据
      * @param transferVO 设备数据传输请求参数
@@ -207,29 +244,12 @@ public class DeviceDataQuery {
      * @return 模拟数据列表
      */
     private List<JSONObject> generateSimulationData(Integer deviceType, List<DmpDevice> devices) {
+
+        Map<String, Double> stringDoubleMap = WeatherFetcher.fetchWeather();
+
         List<JSONObject> simulationList = new ArrayList<>();
         long currentTime = System.currentTimeMillis();
 
-        // 定义模拟数据范围常量
-        final double TEMP_RANGE_MIN = 10.0;
-        final double TEMP_RANGE_MAX = 20.0;
-        final double HUMIDITY_RANGE_MIN = 40.0;
-        final double HUMIDITY_RANGE_MAX = 85.0;
-        final double OXYGEN_RANGE_MIN = 20.0;
-        final double OXYGEN_RANGE_MAX = 21.0;
-        final double CO2_RANGE_MIN = 750.0;
-        final double CO2_RANGE_MAX = 760.0;
-        final double VOLTAGE_RANGE_MIN = 220.0;
-        final double VOLTAGE_RANGE_MAX = 230.0;
-        final double CURRENT_RANGE_MIN = 0.0;
-        final double CURRENT_RANGE_MAX = 50.0;
-        final double POWER_RANGE_MIN = 1.0;
-        final double POWER_RANGE_MAX = 20.0;
-        final double TEMP_LINE_RANGE_MIN = 20.0;
-        final double TEMP_LINE_RANGE_MAX = 50.0;
-        final double LEAKAGE_CURRENT_RANGE_MIN = 0.0;
-        final double LEAKAGE_CURRENT_RANGE_MAX = 100.0;
-
         for (DmpDevice device : devices) {
             JSONObject simulationData = new JSONObject();
             simulationData.put("time", currentTime);
@@ -243,14 +263,19 @@ public class DeviceDataQuery {
             switch (deviceType) {
                 // 单一温度传感器(707)
                 case 707:
-                    double temp707 = ThreadLocalRandom.current().nextDouble(TEMP_RANGE_MIN, TEMP_RANGE_MAX);
+                    double temp707 = 0.0;
+                    if (stringDoubleMap.isEmpty()) {
+                        temp707 = ThreadLocalRandom.current().nextDouble(TEMP_RANGE_MIN, TEMP_RANGE_MAX);
+                    } else {
+                        double floating = ThreadLocalRandom.current().nextDouble(FLOATING_RANGE_MIN, FLOATING_RANGE_MAX);
+                        temp707 = stringDoubleMap.get("temperature") + 0.5 + floating;
+                    }
                     simulationData.put("wd", formatNumber(temp707, FORMAT_2_2));
                     break;
 
                 // 单一湿度传感器(708)
                 case 708:
-                    double hum708 = ThreadLocalRandom.current().nextDouble(HUMIDITY_RANGE_MIN, HUMIDITY_RANGE_MAX);
-                    simulationData.put("sd", formatNumber(hum708, FORMAT_2_2));
+                    simulationData.put("sd", formatNumber(ThreadLocalRandom.current().nextDouble(HUMIDITY_RANGE_MIN, HUMIDITY_RANGE_MAX), FORMAT_2_2));
                     break;
 
                 // 单一氧气传感器(709)
@@ -283,23 +308,37 @@ public class DeviceDataQuery {
                 // 电气火灾(704)
                 case 704:
                     // A/B/C相电压:3位整数+2位小数(220.00~230.00V)
-                    simulationData.put("aVoltage", formatNumber(ThreadLocalRandom.current().nextDouble(VOLTAGE_RANGE_MIN, VOLTAGE_RANGE_MAX), FORMAT_3_2));
-                    simulationData.put("bVoltage", formatNumber(ThreadLocalRandom.current().nextDouble(VOLTAGE_RANGE_MIN, VOLTAGE_RANGE_MAX), FORMAT_3_2));
-                    simulationData.put("cVoltage", formatNumber(ThreadLocalRandom.current().nextDouble(VOLTAGE_RANGE_MIN, VOLTAGE_RANGE_MAX), FORMAT_3_2));
-
-                    // A/B/C相电流:3位整数+2位小数(0.00~50.00A)
-                    simulationData.put("aElectricity", formatNumber(ThreadLocalRandom.current().nextDouble(CURRENT_RANGE_MIN, CURRENT_RANGE_MAX), FORMAT_3_2));
-                    simulationData.put("bElectricity", formatNumber(ThreadLocalRandom.current().nextDouble(CURRENT_RANGE_MIN, CURRENT_RANGE_MAX), FORMAT_3_2));
-                    simulationData.put("cElectricity", formatNumber(ThreadLocalRandom.current().nextDouble(CURRENT_RANGE_MIN, CURRENT_RANGE_MAX), FORMAT_3_2));
+                    double aVoltage = ThreadLocalRandom.current().nextDouble(VOLTAGE_RANGE_MIN, VOLTAGE_RANGE_MAX);
+                    simulationData.put("aVoltage", formatNumber(aVoltage, FORMAT_3_2));
+                    double bVoltage = ThreadLocalRandom.current().nextDouble(VOLTAGE_RANGE_MIN, VOLTAGE_RANGE_MAX);
+                    simulationData.put("bVoltage", formatNumber(bVoltage, FORMAT_3_2));
+                    double cVoltage = ThreadLocalRandom.current().nextDouble(VOLTAGE_RANGE_MIN, VOLTAGE_RANGE_MAX);
+                    simulationData.put("cVoltage", formatNumber(cVoltage, FORMAT_3_2));
+
+                    // A/B/C相电流:3位整数+2位小数(0.00~1.50A)
+                    String deviceId = device.getDeviceId();
+                    double aElectricity = getCurrentValue(deviceId, "a");
+                    simulationData.put("aElectricity", formatNumber(aElectricity, FORMAT_3_2));
+                    double bElectricity = getCurrentValue(deviceId, "b");
+                    simulationData.put("bElectricity", formatNumber(bElectricity, FORMAT_3_2));
+                    double cElectricity = getCurrentValue(deviceId, "c");
+                    simulationData.put("cElectricity", formatNumber(cElectricity, FORMAT_3_2));
 
                     // 总功率:4位整数+2位小数(1.00~20.00)
-                    simulationData.put("totalPower", formatNumber(ThreadLocalRandom.current().nextDouble(POWER_RANGE_MIN, POWER_RANGE_MAX), FORMAT_4_2));
-
-                    // 线温1-4:2位整数+2位小数(20.00~50.00℃)
-                    simulationData.put("line1TEMP", formatNumber(ThreadLocalRandom.current().nextDouble(TEMP_LINE_RANGE_MIN, TEMP_LINE_RANGE_MAX), FORMAT_2_2));
-                    simulationData.put("Line2TEMP", formatNumber(ThreadLocalRandom.current().nextDouble(TEMP_LINE_RANGE_MIN, TEMP_LINE_RANGE_MAX), FORMAT_2_2));
-                    simulationData.put("Line3TEMP", formatNumber(ThreadLocalRandom.current().nextDouble(TEMP_LINE_RANGE_MIN, TEMP_LINE_RANGE_MAX), FORMAT_2_2));
-                    simulationData.put("Line4TEMP", formatNumber(ThreadLocalRandom.current().nextDouble(TEMP_LINE_RANGE_MIN, TEMP_LINE_RANGE_MAX), FORMAT_2_2));
+                    double totalPower = (aVoltage * aElectricity + bVoltage * bElectricity + cVoltage * cElectricity) / 1000;
+                    simulationData.put("totalPower", formatNumber(totalPower, FORMAT_4_2));
+
+                    // 线温1-4:2位整数+2位小数(20.00~50.00℃)+1.0 +0.5
+                    double lineTemp = 0.0;
+                    if (stringDoubleMap.isEmpty()) {
+                        lineTemp = ThreadLocalRandom.current().nextDouble(TEMP_LINE_RANGE_MIN, TEMP_LINE_RANGE_MAX);
+                    } else {
+                        lineTemp = stringDoubleMap.get("temperature") + 1.0;
+                    }
+                    simulationData.put("line1TEMP", formatNumber(lineTemp + ThreadLocalRandom.current().nextDouble(FLOATING_RANGE_MIN1, FLOATING_RANGE_MAX1), FORMAT_2_2));
+                    simulationData.put("Line2TEMP", formatNumber(lineTemp + ThreadLocalRandom.current().nextDouble(FLOATING_RANGE_MIN1, FLOATING_RANGE_MAX1), FORMAT_2_2));
+                    simulationData.put("Line3TEMP", formatNumber(lineTemp + ThreadLocalRandom.current().nextDouble(FLOATING_RANGE_MIN1, FLOATING_RANGE_MAX1), FORMAT_2_2));
+                    simulationData.put("Line4TEMP", formatNumber(lineTemp + ThreadLocalRandom.current().nextDouble(FLOATING_RANGE_MIN1, FLOATING_RANGE_MAX1), FORMAT_2_2));
 
                     // 剩余电流:4位整数+2位小数(0.00~100.00mA)
                     simulationData.put("leakageCurrent", formatNumber(ThreadLocalRandom.current().nextDouble(LEAKAGE_CURRENT_RANGE_MIN, LEAKAGE_CURRENT_RANGE_MAX), FORMAT_4_2));
@@ -330,4 +369,42 @@ public class DeviceDataQuery {
         return format.format(value);
     }
 
+    // ========== 获取带缓存的电流值 ==========
+    private double getCurrentValue(String deviceId, String phase) {
+
+        // 构建设备+相的唯一缓存Key(核心!)
+        String cacheKey = deviceId + "_" + phase;
+        // 后续逻辑不变,只是把所有phase替换为cacheKey
+        int currentReuseCount = currentReuseCountCache.getOrDefault(cacheKey, 0);
+
+        System.out.println("cacheKey=" + cacheKey +
+                " 命中=" + currentValueCache.containsKey(cacheKey) +
+                " 复用次数=" + currentReuseCountCache.getOrDefault(cacheKey, 0) +
+                "值=" + currentValueCache.get(cacheKey));
+
+        if (!currentValueCache.containsKey(cacheKey) || currentReuseCount >= MAX_REUSE_COUNT) {
+            return generateNewCurrent(cacheKey);
+        }
+
+        boolean reuse = ThreadLocalRandom.current().nextDouble() < REUSE_PROBABILITY;
+        if (reuse) {
+            int newReuseCount = currentReuseCount + 1;
+            currentReuseCountCache.put(cacheKey, newReuseCount);
+            System.out.println("复用值=" + currentValueCache.get(cacheKey));
+            return currentValueCache.get(cacheKey);
+        } else {
+            double newValue = generateNewCurrent(cacheKey);
+            System.out.println("生成新值=" + newValue);
+            return newValue;
+        }
+    }
+
+    // 同步修改generateNewCurrent方法(参数改为cacheKey)
+    private double generateNewCurrent(String cacheKey) {
+        double newValue = ThreadLocalRandom.current().nextDouble(CURRENT_RANGE_MIN, CURRENT_RANGE_MAX);
+        newValue = Math.round(newValue * 100.0) / 100.0;
+        currentValueCache.put(cacheKey, newValue);
+        currentReuseCountCache.put(cacheKey, 0);
+        return newValue;
+    }
 }

+ 1 - 7
service-cdi/service-cdi-biz/src/main/java/com/usky/cdi/service/util/DeviceDataSyncService.java

@@ -26,19 +26,13 @@ public class DeviceDataSyncService {
      * fixedDelay:任务执行完成后固定延迟29分钟执行下一次
      * initialDelay:初始化后立即执行第一次任务
      */
-    //@Scheduled(fixedDelay = 29 * 60 * 1000, initialDelay = 0)
+    //@Scheduled(fixedDelay = 60 * 1000, initialDelay = 0)
     public void scheduledDeviceDataSync() {
         Integer tenantId = 1208;
         Long engineeringId = 3101130019L;
         log.info("开始执行设备数据同步定时任务,租户ID:{},工程ID:{}", tenantId, engineeringId);
 
         try {
-            // 参数验证
-            if (engineeringId == null) {
-                log.error("设备数据同步失败:工程ID不能为空");
-                return;
-            }
-
             iotDataTransferService.synchronizeDeviceData(tenantId, engineeringId);
         } catch (Exception e) {
             log.error("定时任务执行设备数据同步失败:{}", e.getMessage(), e);

+ 92 - 0
service-cdi/service-cdi-biz/src/main/java/com/usky/cdi/service/util/WeatherFetcher.java

@@ -0,0 +1,92 @@
+package com.usky.cdi.service.util;
+
+import java.io.BufferedReader;
+import java.io.InputStreamReader;
+import java.net.HttpURLConnection;
+import java.net.URL;
+import java.util.HashMap;
+import java.util.Map;
+
+import org.json.JSONObject;
+
+/**
+ *
+ * @author fyc
+ * @email yuchuan.fu@chinausky.com
+ * @date 2025/12/15
+ */
+
+public class WeatherFetcher {
+    private static final String API_KEY = "d04f0f84421a99b9b66dd99243c36db4";
+    private static final String CITY_NAME = "shanghai,cn";
+    private static final String API_URL = "https://api.openweathermap.org/data/2.5/weather?q=" + CITY_NAME + "&appid=" + API_KEY;
+
+    public static Map<String, Double> fetchWeather() {
+        double tempCelsius = 0.0;
+        int humidity = 0;
+        try {
+            // 1. 构造请求URL
+            URL url = new URL(API_URL);
+
+            // 2. 建立连接并发送请求
+            HttpURLConnection conn = (HttpURLConnection) url.openConnection();
+            conn.setRequestMethod("GET");
+
+            // 3. 读取响应
+            BufferedReader reader = new BufferedReader(new InputStreamReader(conn.getInputStream()));
+            StringBuilder response = new StringBuilder();
+            String line;
+            while ((line = reader.readLine()) != null) {
+                response.append(line);
+            }
+            reader.close();
+
+            // 4. 解析JSON数据(这里使用了org.json库)
+            JSONObject jsonResponse = new JSONObject(response.toString());
+            JSONObject main = jsonResponse.getJSONObject("main");
+
+            // 1. 提取基础信息
+            String cityName = jsonResponse.getString("name");
+            int timezoneOffset = jsonResponse.getInt("timezone");
+
+            // 注意:温度默认是开尔文单位,转换为摄氏度需要 -273.15
+            double tempKelvin = main.getDouble("temp");
+            tempCelsius = tempKelvin - 273.15;
+            humidity = main.getInt("humidity");
+            double feelsLikeKelvin = main.getDouble("feels_like");
+            double feelsLikeCelsius = feelsLikeKelvin - 273.15;
+
+            // 3. 提取天气状况描述
+            JSONObject weather = jsonResponse.getJSONArray("weather").getJSONObject(0);
+            String description = weather.getString("description");
+
+            // 4. 输出解析结果
+            System.out.println("=== 天气解析结果 ===");
+            System.out.println("城市: " + cityName);
+            System.out.println("温度: " + String.format("%.2f", tempCelsius) + "°C (原始: " + tempKelvin + "K)");
+            System.out.println("体感温度: " + String.format("%.2f", feelsLikeCelsius) + "°C");
+            System.out.println("湿度: " + humidity + "%");
+            System.out.println("天气状况: " + description);
+            System.out.println("时区偏移: " + (timezoneOffset / 3600) + "小时");
+
+            // 5. 检查是否包含臭氧数据
+            if (jsonResponse.has("air_quality") || jsonResponse.has("o3") || jsonResponse.has("components")) {
+                System.out.println("包含空气质量数据");
+            } else {
+                System.out.println("提示: 当前数据不包含臭氧浓度等空气质量指标。");
+            }
+
+        } catch (Exception e) {
+            System.err.println("解析JSON时出错: " + e.getMessage());
+            e.printStackTrace();
+        }
+        Map<String, Double> resultMap = new HashMap<>();
+        resultMap.put("temperature", tempCelsius);
+        resultMap.put("humidity", (double) humidity);
+        return resultMap;
+    }
+
+    public static void main(String[] args) {
+        fetchWeather();
+    }
+}

+ 69 - 0
service-cdi/service-cdi-biz/src/main/java/com/usky/cdi/service/vo/alarm/AlarmMessage1VO.java

@@ -0,0 +1,69 @@
+package com.usky.cdi.service.vo.alarm;
+
+import lombok.Data;
+
+@Data
+public class AlarmMessage1VO {
+    private static final long serialVersionUID = 1L;
+
+    /**
+     * 数据包ID
+     */
+    private Long dataPacketID;
+
+    /**
+     * 人防工程ID
+     */
+    private Long engineeringID;
+
+    /**
+     * 事件ID
+     */
+    private Integer alarmID;
+
+    /**
+     * 事件来源
+     */
+    private Integer alarmSource;
+
+    /**
+     * 物联设施ID
+     */
+    private Integer sensorID;
+
+    /**
+     * 事件类型
+     */
+    private String alarmType;
+
+    /**
+     * 事件状态
+     */
+    private Integer alarmStatus;
+
+    /**
+     * 最新水浸状态
+     */
+    private Integer sensorValue;
+
+    /**
+     * 事件发生/更新时间
+     */
+    private String alarmUpdateTime;
+
+    /**
+     * 监测对象编号
+     */
+    private String monitorObjNo;
+
+    /**
+     * 事件描述
+     */
+    private String alarmDesc;
+
+    /**
+     * 上报时间
+     */
+    private String publishTime;
+
+}

+ 69 - 0
service-cdi/service-cdi-biz/src/main/java/com/usky/cdi/service/vo/alarm/AlarmMessage2VO.java

@@ -0,0 +1,69 @@
+package com.usky.cdi.service.vo.alarm;
+
+import lombok.Data;
+
+@Data
+public class AlarmMessage2VO {
+    private static final long serialVersionUID = 1L;
+
+    /**
+     * 数据包ID
+     */
+    private Long dataPacketID;
+
+    /**
+     * 人防工程ID
+     */
+    private Long engineeringID;
+
+    /**
+     * 事件ID
+     */
+    private Integer alarmID;
+
+    /**
+     * 事件来源
+     */
+    private Integer alarmSource;
+
+    /**
+     * 防护单元
+     */
+    private String unitName;
+
+    /**
+     * 事件类型
+     */
+    private String alarmType;
+
+    /**
+     * 事件状态
+     */
+    private Integer alarmStatus;
+
+    /**
+     * 倾斜、位移、裂缝监测结果
+     */
+    private Double sensorValue;
+
+    /**
+     * 事件发生/更新时间
+     */
+    private String alarmUpdateTime;
+
+    /**
+     * 监测对象编号
+     */
+    private String monitorObjNo;
+
+    /**
+     * 事件描述
+     */
+    private String alarmDesc;
+
+    /**
+     * 上报时间
+     */
+    private String publishTime;
+
+}

+ 79 - 0
service-cdi/service-cdi-biz/src/main/java/com/usky/cdi/service/vo/alarm/AlarmMessage3VO.java

@@ -0,0 +1,79 @@
+package com.usky.cdi.service.vo.alarm;
+
+import lombok.Data;
+
+@Data
+public class AlarmMessage3VO {
+    private static final long serialVersionUID = 1L;
+
+    /**
+     * 数据包ID
+     */
+    private Long dataPacketID;
+
+    /**
+     * 人防工程ID
+     */
+    private Long engineeringID;
+
+    /**
+     * 事件ID
+     */
+    private Integer alarmID;
+
+    /**
+     * 事件来源
+     */
+    private Integer alarmSource;
+
+    /**
+     * 物联设施ID
+     */
+    private Integer sensorID;
+
+    /**
+     * 事件类型
+     */
+    private String alarmType;
+
+    /**
+     * 事件状态
+     */
+    private Integer alarmStatus;
+
+    /**
+     * 告警时的电流
+     */
+    private Double sensorValue;
+
+    /**
+     * 告警阈值
+     */
+    private Double thresholding;
+
+    /**
+     * 线缆序号
+     */
+    private Integer lineNo;
+
+    /**
+     * 事件发生/更新时间
+     */
+    private String alarmUpdateTime;
+
+    /**
+     * 监测对象编号
+     */
+    private String monitorObjNo;
+
+    /**
+     * 事件描述
+     */
+    private String alarmDesc;
+
+    /**
+     * 上报时间
+     */
+    private String publishTime;
+
+}

+ 74 - 0
service-cdi/service-cdi-biz/src/main/java/com/usky/cdi/service/vo/alarm/AlarmMessageVO.java

@@ -0,0 +1,74 @@
+package com.usky.cdi.service.vo.alarm;
+
+import lombok.Data;
+
+@Data
+public class AlarmMessageVO {
+    private static final long serialVersionUID = 1L;
+
+    /**
+     * 数据包ID
+     */
+    private Long dataPacketID;
+
+    /**
+     * 人防工程ID
+     */
+    private Long engineeringID;
+
+    /**
+     * 事件ID
+     */
+    private Integer alarmID;
+
+    /**
+     * 事件来源
+     */
+    private Integer alarmSource;
+
+    /**
+     * 物联设施ID
+     */
+    private Integer sensorID;
+
+    /**
+     * 事件类型
+     */
+    private String alarmType;
+
+    /**
+     * 事件状态
+     */
+    private Integer alarmStatus;
+
+    /**
+     * 最新水浸状态
+     */
+    private Double sensorValue;
+
+    /**
+     * 告警阈值
+     */
+    private Double thresholding;
+
+    /**
+     * 事件发生/更新时间
+     */
+    private String alarmUpdateTime;
+
+    /**
+     * 监测对象编号
+     */
+    private String monitorObjNo;
+
+    /**
+     * 事件描述
+     */
+    private String alarmDesc;
+
+    /**
+     * 上报时间
+     */
+    private String publishTime;
+
+}

+ 161 - 0
service-cdi/service-cdi-biz/src/main/java/com/usky/cdi/service/vo/base/FacilityDeviceVO.java

@@ -0,0 +1,161 @@
+package com.usky.cdi.service.vo.base;
+
+import lombok.Data;
+import java.io.Serializable;
+import java.time.LocalDateTime;
+
+/**
+ * 楼层平面图信息VO
+ * Topic: base/floorPlane
+ * 
+ * @author han
+ * @date 2025/03/20
+ */
+@Data
+public class FacilityDeviceVO implements Serializable {
+    private static final long serialVersionUID = 1L;
+
+    private Integer id;
+
+    /**
+     * 设施编号
+     */
+    private String facilityNum;
+
+    /**
+     * 设施名称
+     */
+    private String facilityName;
+
+    /**
+     * 设施类型
+     */
+    private String facilityType;
+
+    /**
+     * 所属楼层
+     */
+    private String floor;
+
+    /**
+     * 安装位置
+     */
+    private String address;
+
+    /**
+     * 图⽚地址URL
+     */
+    private String imagesUrl;
+
+    /**
+     * 设备ID
+     */
+    private String deviceId;
+
+    /**
+     * 联系人
+     */
+    private String contact;
+
+    /**
+     * 联系方式
+     */
+    private String contactPhone;
+
+    /**
+     * 平面X轴坐标
+     */
+    private String planeX;
+
+    /**
+     * 平面Y轴坐标
+     */
+    private String planeY;
+
+    private String coordinateX;
+
+    private String coordinateY;
+
+    private String coordinateZ;
+
+    /**
+     * 删除标识
+     */
+    private Integer deleteFlag;
+
+    /**
+     * 创建时间
+     */
+    private LocalDateTime createTime;
+
+    /**
+     * 更新时间
+     */
+    private LocalDateTime updateTime;
+
+    /**
+     * 更新人
+     */
+    private String updateBy;
+
+    /**
+     * 创建人
+     */
+    private String createBy;
+
+    /**
+     * 组织结构ID
+     */
+    private Integer deptId;
+
+    /**
+     * 租户ID
+     */
+    private Integer tenantId;
+
+    /**
+     * 建筑设施备注
+     */
+    private String facilityDesc;
+
+    /**
+     * 三维角度X
+     */
+    private Double anglesX;
+
+    /**
+     * 三维角度y
+     */
+    private Double anglesY;
+
+    /**
+     * 三维角度z
+     */
+    private Double anglesZ;
+
+    /**
+     * 三维图标大小
+     */
+    private Double scaleL;
+
+    /**
+     * 三维图标大小
+     */
+    private Double scaleW;
+
+    /**
+     * 三维图标大小
+     */
+    private Double scaleH;
+
+    /**
+     * 设备类型
+     */
+    private Integer deviceType;
+
+    /**
+     * 设备UUID
+     */
+    private String deviceUuid;
+}
+

+ 6 - 6
service-cdi/service-cdi-biz/src/main/java/com/usky/cdi/service/vo/base/SensorInfoVO.java

@@ -70,18 +70,18 @@ public class SensorInfoVO implements Serializable {
     private Long floorFileID;
 
     /**
-     * 设施在平面图的X轴坐标
+     * 上报时间
      */
-    private Integer xCoordinate;
+    private String publishTime;
 
     /**
-     * 设施在平面图的Y轴坐标
+     * 设施在平面图的X轴坐标
      */
-    private Integer yCoordinate;
+    private Long x;
 
     /**
-     * 上报时间
+     * 设施在平面图的Y轴坐标
      */
-    private String publishTime;
+    private Long y;
 }
 

+ 38 - 0
service-cdi/service-cdi-biz/src/main/resources/mapper/cdi/BaseBuildFacilityMapper.xml

@@ -0,0 +1,38 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
+<mapper namespace="com.usky.cdi.mapper.BaseBuildFacilityMapper">
+
+    <!-- 通用查询映射结果 -->
+    <resultMap id="BaseResultMap" type="com.usky.cdi.domain.BaseBuildFacility">
+        <id column="id" property="id" />
+        <result column="facility_num" property="facilityNum" />
+        <result column="facility_name" property="facilityName" />
+        <result column="facility_type" property="facilityType" />
+        <result column="floor" property="floor" />
+        <result column="address" property="address" />
+        <result column="images_url" property="imagesUrl" />
+        <result column="device_id" property="deviceId" />
+        <result column="contact" property="contact" />
+        <result column="contact_phone" property="contactPhone" />
+        <result column="plane_x" property="planeX" />
+        <result column="plane_y" property="planeY" />
+        <result column="coordinate_x" property="coordinateX" />
+        <result column="coordinate_y" property="coordinateY" />
+        <result column="coordinate_z" property="coordinateZ" />
+        <result column="delete_flag" property="deleteFlag" />
+        <result column="create_time" property="createTime" />
+        <result column="update_time" property="updateTime" />
+        <result column="update_by" property="updateBy" />
+        <result column="create_by" property="createBy" />
+        <result column="dept_id" property="deptId" />
+        <result column="tenant_id" property="tenantId" />
+        <result column="facility_desc" property="facilityDesc" />
+        <result column="angles_x" property="anglesX" />
+        <result column="angles_y" property="anglesY" />
+        <result column="angles_z" property="anglesZ" />
+        <result column="scale_l" property="scaleL" />
+        <result column="scale_w" property="scaleW" />
+        <result column="scale_h" property="scaleH" />
+    </resultMap>
+
+</mapper>

+ 1 - 1
service-cdi/service-cdi-biz/src/main/resources/mapper/cdi/DmpDeviceMapper.xml

@@ -1,6 +1,6 @@
 <?xml version="1.0" encoding="UTF-8"?>
 <!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
-<mapper namespace="com.usky.alarm.mapper.DmpDeviceMapper">
+<mapper namespace="com.usky.cdi.mapper.DmpDeviceMapper">
 
     <!-- 通用查询映射结果 -->
     <resultMap id="BaseResultMap" type="com.usky.cdi.domain.DmpDevice">