瀏覽代碼

断路器电量计算

learshaw 4 月之前
父節點
當前提交
0f47170777
共有 25 個文件被更改,包括 729 次插入184 次删除
  1. 13 13
      ems/ems-application/ems-admin/src/main/java/com/ruoyi/web/controller/ems/ElecPriceController.java
  2. 1 2
      ems/ems-application/ems-admin/src/main/java/com/ruoyi/web/controller/ems/MeterReadingController.java
  3. 2 0
      ems/ems-cloud/ems-dev-adapter/src/main/java/com/ruoyi/ems/EmsDevAdpApplication.java
  4. 2 2
      ems/ems-cloud/ems-dev-adapter/src/main/java/com/ruoyi/ems/core/MessageCache.java
  5. 131 98
      ems/ems-cloud/ems-dev-adapter/src/main/java/com/ruoyi/ems/handle/GeekOpenCbHandler.java
  6. 179 6
      ems/ems-cloud/ems-dev-adapter/src/main/java/com/ruoyi/ems/handle/MqttBaseHandler.java
  7. 1 1
      ems/ems-cloud/ems-dev-adapter/src/main/java/com/ruoyi/ems/handle/RootMsgHandler.java
  8. 1 1
      ems/ems-cloud/ems-dev-adapter/src/main/resources/application-local.yml
  9. 13 13
      ems/ems-cloud/ems-server/src/main/java/com/ruoyi/ems/controller/ElecPriceController.java
  10. 1 2
      ems/ems-cloud/ems-server/src/main/java/com/ruoyi/ems/controller/MeterReadingController.java
  11. 3 3
      ems/ems-core/src/main/java/com/ruoyi/ems/domain/ElecPriceStrategy.java
  12. 3 3
      ems/ems-core/src/main/java/com/ruoyi/ems/domain/ElecPriceStrategyHour.java
  13. 35 0
      ems/ems-core/src/main/java/com/ruoyi/ems/enums/DevOnlineStatus.java
  14. 9 0
      ems/ems-core/src/main/java/com/ruoyi/ems/mapper/ElecGwPriceConfigMapper.java
  15. 2 2
      ems/ems-core/src/main/java/com/ruoyi/ems/mapper/MeterDeviceMapper.java
  16. 84 0
      ems/ems-core/src/main/java/com/ruoyi/ems/model/Price.java
  17. 20 12
      ems/ems-core/src/main/java/com/ruoyi/ems/service/IElecPriceConfigService.java
  18. 1 2
      ems/ems-core/src/main/java/com/ruoyi/ems/service/IMeterDeviceService.java
  19. 34 0
      ems/ems-core/src/main/java/com/ruoyi/ems/service/IPriceService.java
  20. 17 12
      ems/ems-core/src/main/java/com/ruoyi/ems/service/impl/ElecPriceConfigServiceImpl.java
  21. 0 1
      ems/ems-core/src/main/java/com/ruoyi/ems/service/impl/EmsObjAbilityCallLogServiceImpl.java
  22. 2 2
      ems/ems-core/src/main/java/com/ruoyi/ems/service/impl/MeterDeviceServiceImpl.java
  23. 169 0
      ems/ems-core/src/main/java/com/ruoyi/ems/service/impl/PriceServiceImpl.java
  24. 5 8
      ems/ems-core/src/main/resources/mapper/ems/ElecGwPriceConfigMapper.xml
  25. 1 1
      ems/ems-core/src/main/resources/mapper/ems/MeterDeviceMapper.xml

+ 13 - 13
ems/ems-application/ems-admin/src/main/java/com/ruoyi/web/controller/ems/ElecPriceController.java

@@ -44,7 +44,7 @@ public class ElecPriceController extends BaseController {
     @GetMapping("/gw/list")
     public TableDataInfo listGw(ElecGwPriceConfig elecValencyConfig) {
         startPage();
-        List<ElecGwPriceConfig> list = configService.selectGwElecPriceConfigList(elecValencyConfig);
+        List<ElecGwPriceConfig> list = configService.selectGwElecPriceCfgList(elecValencyConfig);
         return getDataTable(list);
     }
 
@@ -55,7 +55,7 @@ public class ElecPriceController extends BaseController {
     @Log(title = "国网电价配置", businessType = BusinessType.EXPORT)
     @PostMapping("/gw/export")
     public void exportGw(HttpServletResponse response, ElecGwPriceConfig elecValencyConfig) {
-        List<ElecGwPriceConfig> list = configService.selectGwElecPriceConfigList(elecValencyConfig);
+        List<ElecGwPriceConfig> list = configService.selectGwElecPriceCfgList(elecValencyConfig);
         ExcelUtil<ElecGwPriceConfig> util = new ExcelUtil<>(ElecGwPriceConfig.class);
         util.exportExcel(response, list, "国网电价配置数据");
     }
@@ -66,7 +66,7 @@ public class ElecPriceController extends BaseController {
     @PreAuthorize("@ss.hasPermi('basecfg:price:query')")
     @GetMapping(value = "/gw/{id}")
     public AjaxResult getGwInfo(@PathVariable("id") Long id) {
-        return success(configService.selectGwElecPriceConfigById(id));
+        return success(configService.selectGwElecPriceCfgById(id));
     }
 
     /**
@@ -76,7 +76,7 @@ public class ElecPriceController extends BaseController {
     @Log(title = "电价配置", businessType = BusinessType.INSERT)
     @PostMapping(value = "/gw")
     public AjaxResult addGw(@RequestBody ElecGwPriceConfig elecValencyConfig) {
-        return toAjax(configService.insertGwElecPriceConfig(elecValencyConfig));
+        return toAjax(configService.insertGwElecPriceCfg(elecValencyConfig));
     }
 
     /**
@@ -86,7 +86,7 @@ public class ElecPriceController extends BaseController {
     @Log(title = "电价配置", businessType = BusinessType.UPDATE)
     @PutMapping(value = "/gw")
     public AjaxResult editGw(@RequestBody ElecGwPriceConfig elecValencyConfig) {
-        return toAjax(configService.updateGwElecPriceConfig(elecValencyConfig));
+        return toAjax(configService.updateGwElecPriceCfg(elecValencyConfig));
     }
 
     /**
@@ -96,7 +96,7 @@ public class ElecPriceController extends BaseController {
     @Log(title = "电价配置", businessType = BusinessType.DELETE)
     @DeleteMapping("/gw/{ids}")
     public AjaxResult removeGw(@PathVariable Long[] ids) {
-        return toAjax(configService.deleteGwElecPriceConfigByIds(ids));
+        return toAjax(configService.deleteGwElecPriceCfgByIds(ids));
     }
 
     /**
@@ -105,7 +105,7 @@ public class ElecPriceController extends BaseController {
      */
     @GetMapping("/gw/listall")
     public AjaxResult listAllGw() {
-        List<ElecGwPriceConfig> list = configService.selectGwElecPriceConfigList(new ElecGwPriceConfig());
+        List<ElecGwPriceConfig> list = configService.selectGwElecPriceCfgList(new ElecGwPriceConfig());
         return success(list);
     }
 
@@ -117,7 +117,7 @@ public class ElecPriceController extends BaseController {
     public TableDataInfo listPv(ElecPvPriceConfig pvPriceConfig)
     {
         startPage();
-        List<ElecPvPriceConfig> list = configService.selectPvPriceConfigList(pvPriceConfig);
+        List<ElecPvPriceConfig> list = configService.selectPvPriceCfgList(pvPriceConfig);
         return getDataTable(list);
     }
 
@@ -129,7 +129,7 @@ public class ElecPriceController extends BaseController {
     @PostMapping("/pv/export")
     public void exportPv(HttpServletResponse response, ElecPvPriceConfig pvPriceConfig)
     {
-        List<ElecPvPriceConfig> list = configService.selectPvPriceConfigList(pvPriceConfig);
+        List<ElecPvPriceConfig> list = configService.selectPvPriceCfgList(pvPriceConfig);
         ExcelUtil<ElecPvPriceConfig> util = new ExcelUtil<>(ElecPvPriceConfig.class);
         util.exportExcel(response, list, "光伏电价配置数据");
     }
@@ -141,7 +141,7 @@ public class ElecPriceController extends BaseController {
     @GetMapping(value = "/pv/{id}")
     public AjaxResult getPvInfo(@PathVariable("id") Long id)
     {
-        return success(configService.selectPvPriceConfigById(id));
+        return success(configService.selectPvPriceCfgById(id));
     }
 
     /**
@@ -152,7 +152,7 @@ public class ElecPriceController extends BaseController {
     @PostMapping(value = "/pv")
     public AjaxResult addPv(@RequestBody ElecPvPriceConfig pvPriceConfig)
     {
-        return toAjax(configService.insertPvPriceConfig(pvPriceConfig));
+        return toAjax(configService.insertPvPriceCfg(pvPriceConfig));
     }
 
     /**
@@ -163,7 +163,7 @@ public class ElecPriceController extends BaseController {
     @PutMapping(value = "/pv")
     public AjaxResult editPv(@RequestBody ElecPvPriceConfig pvPriceConfig)
     {
-        return toAjax(configService.updatePvPriceConfig(pvPriceConfig));
+        return toAjax(configService.updatePvPriceCfg(pvPriceConfig));
     }
 
     /**
@@ -174,6 +174,6 @@ public class ElecPriceController extends BaseController {
     @DeleteMapping("/pv/{ids}")
     public AjaxResult removePv(@PathVariable Long[] ids)
     {
-        return toAjax(configService.deletePvPriceConfigByIds(ids));
+        return toAjax(configService.deletePvPriceCfgByIds(ids));
     }
 }

+ 1 - 2
ems/ems-application/ems-admin/src/main/java/com/ruoyi/web/controller/ems/MeterReadingController.java

@@ -129,8 +129,7 @@ public class MeterReadingController extends BaseController {
     }
 
     private void fillData(MeterReading lastItem, MeterReading meterRec) {
-        MeterDevice meterDevice = meterDeviceService.selectMeterDeviceByCode(meterRec.getAreaCode(),
-            meterRec.getDeviceCode());
+        MeterDevice meterDevice = meterDeviceService.selectMeterDeviceByCode(meterRec.getDeviceCode());
         Date date = new Date();
 
         if (null != lastItem) {

+ 2 - 0
ems/ems-cloud/ems-dev-adapter/src/main/java/com/ruoyi/ems/EmsDevAdpApplication.java

@@ -7,6 +7,7 @@ import org.springframework.boot.SpringApplication;
 import org.springframework.boot.autoconfigure.SpringBootApplication;
 import org.springframework.boot.autoconfigure.data.redis.RedisAutoConfiguration;
 import org.springframework.scheduling.annotation.EnableAsync;
+import org.springframework.scheduling.annotation.EnableScheduling;
 
 /**
  * 能源设备适配器
@@ -15,6 +16,7 @@ import org.springframework.scheduling.annotation.EnableAsync;
  */
 @EnableCustomConfig
 @EnableCustomSwagger2
+@EnableScheduling
 @EnableAsync
 @SpringBootApplication(scanBasePackages = { "com.ruoyi.ems","com.ruoyi.system" })
 public class EmsDevAdpApplication {

+ 2 - 2
ems/ems-cloud/ems-dev-adapter/src/main/java/com/ruoyi/ems/core/MessageCache.java

@@ -38,10 +38,10 @@ public class MessageCache {
     /**
      * 定时清理过期的消息
      */
-    @Scheduled(fixedRate = 3600000)
+    @Scheduled(cron = "0 0/5 * * * ?")
     public void cleanUpOldMessages() {
         long currentTime = new Date().getTime();
-        long threshold = 60 * 60 * 1000; // 1小时
+        long threshold = 5 * 60 * 1000; // 分钟
 
         Iterator<Map.Entry<String, MqttCacheMsg>> iterator = mqttMessageMap.entrySet().iterator();
         while (iterator.hasNext()) {

+ 131 - 98
ems/ems-cloud/ems-dev-adapter/src/main/java/com/ruoyi/ems/handle/GeekOpenCbHandler.java

@@ -13,35 +13,36 @@ package com.ruoyi.ems.handle;
 import com.alibaba.fastjson2.JSONObject;
 import com.huashe.common.exception.Assert;
 import com.huashe.common.exception.BusinessException;
+import com.huashe.common.utils.DateUtils;
 import com.huashe.common.utils.ThreadUtils;
 import com.ruoyi.ems.core.MessageCache;
-import com.ruoyi.ems.core.MqttTemplate;
+import com.ruoyi.ems.domain.ElecMeterH;
 import com.ruoyi.ems.domain.EmsDevice;
 import com.ruoyi.ems.domain.EmsObjAbilityCallLog;
-import com.ruoyi.ems.domain.EmsObjAttrValue;
+import com.ruoyi.ems.domain.MeterDevice;
 import com.ruoyi.ems.enums.DevObjType;
+import com.ruoyi.ems.enums.DevOnlineStatus;
 import com.ruoyi.ems.model.AbilityPayload;
 import com.ruoyi.ems.model.MqttCacheMsg;
-import com.ruoyi.ems.service.IEmsDeviceService;
+import com.ruoyi.ems.model.Price;
+import com.ruoyi.ems.service.IElecMeterHService;
 import com.ruoyi.ems.service.IEmsObjAbilityCallLogService;
-import com.ruoyi.ems.service.IEmsObjAttrService;
-import com.ruoyi.ems.service.IEmsObjAttrValueService;
+import com.ruoyi.ems.service.IMeterDeviceService;
+import com.ruoyi.ems.service.IPriceService;
 import com.ruoyi.ems.util.IdUtils;
-import org.apache.commons.collections4.CollectionUtils;
 import org.apache.commons.lang3.StringUtils;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 import org.springframework.beans.factory.annotation.Autowired;
-import org.springframework.beans.factory.annotation.Qualifier;
 import org.springframework.scheduling.annotation.Async;
 import org.springframework.stereotype.Service;
 
-import javax.annotation.Resource;
+import java.math.BigDecimal;
+import java.time.LocalDateTime;
+import java.time.format.DateTimeFormatter;
+import java.time.temporal.ChronoUnit;
 import java.util.Date;
-import java.util.List;
 import java.util.Map;
-import java.util.concurrent.ConcurrentHashMap;
-import java.util.stream.Collectors;
 
 /**
  * GeekOpen 断路器服务层
@@ -56,33 +57,24 @@ import java.util.stream.Collectors;
 public class GeekOpenCbHandler extends MqttBaseHandler {
     private static final Logger log = LoggerFactory.getLogger(GeekOpenCbHandler.class);
 
-    @Resource
-    @Qualifier("mqttTemplate")
-    private MqttTemplate mqttTemplate;
-
     @Autowired
     private MessageCache messageCache;
 
     @Autowired
-    private IEmsDeviceService deviceService;
+    private IEmsObjAbilityCallLogService objAbilityCallLogService;
 
     @Autowired
-    private IEmsObjAttrService objAttrService;
+    private IMeterDeviceService meterDeviceService;
 
     @Autowired
-    private IEmsObjAttrValueService objAttrValueService;
+    private IElecMeterHService elecMeterHService;
 
     @Autowired
-    private IEmsObjAbilityCallLogService objAbilityCallLogService;
-
-    /**
-     * 缓存设备属性
-     */
-    private static final Map<String, Map<String, String>> attrCache = new ConcurrentHashMap<>();
+    private IPriceService priceService;
 
     private static final String TOPIC_PREFIX = "/device/dlq/";
 
-    private static final Integer DEVICE_OBJ_TYPE = DevObjType.DEVC.getCode();
+    private static final DateTimeFormatter TIME_FORMATTER = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss");
 
     /**
      * 能力执行
@@ -94,14 +86,14 @@ public class GeekOpenCbHandler extends MqttBaseHandler {
     public String call(AbilityPayload abilityParam) {
         String retStr = "执行成功!";
 
-        String messageId = IdUtils.generateMessageId();
+        String messageId = "CALL-" + IdUtils.generateMessageId();
         String deviceCode = abilityParam.getObjCode();
         String msgBody = addMsgId(abilityParam.getAbilityParam(), "messageId", messageId);
 
         // 发送消息到MQTT服务器
         long sendTime = System.currentTimeMillis();
         String topic = TOPIC_PREFIX + deviceCode;
-        mqttTemplate.send(topic, msgBody, 2, false);
+        sendMqttMsg(topic, msgBody, 2, false);
 
         // 写入日志
         EmsObjAbilityCallLog logItem = saveLog(abilityParam, sendTime, 1);
@@ -130,7 +122,9 @@ public class GeekOpenCbHandler extends MqttBaseHandler {
 
                 ThreadUtils.sleep(100);
 
-                if (System.currentTimeMillis() - sendTime > 60000) {
+                if (System.currentTimeMillis() - sendTime > 20000) {
+                    EmsDevice device = deviceService.selectByCode(deviceCode);
+                    refreshStatus(device, DevOnlineStatus.OFFLINE);
                     retStr = "响应超时!";
                     break;
                 }
@@ -148,21 +142,27 @@ public class GeekOpenCbHandler extends MqttBaseHandler {
 
             if (null != device) {
                 JSONObject msgBody = JSONObject.parseObject(payload);
-                refreshStatus(device);
-
                 String messageId = msgBody.getString("messageId");
 
+                // 自动上报数据: 1.更新属性值,2.更新电量计量数据
                 if (StringUtils.equals("auto", messageId)) {
                     updateAutoAttr(device, msgBody);
                 }
-                else if (StringUtils.isNotEmpty(messageId)) {
+                // 前序调用的响应消息:1.写入消息队列,2.更新属性值
+                else if (StringUtils.isNotEmpty(messageId) && StringUtils.startsWith(messageId, "CALL-")) {
                     MqttCacheMsg mqttCacheMsg = new MqttCacheMsg(messageId, deviceCode, new Date(), payload);
                     messageCache.addMqttMessage(messageId, mqttCacheMsg);
                     updateBaseAttr(device, msgBody);
                 }
+                // 设备同步数据(INFO类,协议类):更新基础属性值
                 else {
                     updateBaseAttr(device, msgBody);
                 }
+
+                // 设备消息抵达,将数据库离线状态改为在线
+                refreshStatus(device, DevOnlineStatus.ONLINE);
+                // 设备消息抵达,更新最后消息时间
+                updateMsgTime(device, new Date());
             }
             else {
                 log.warn("接收消息,设备未注册, deviceCode:{}\nmessageBody:{}", deviceCode, payload);
@@ -173,14 +173,87 @@ public class GeekOpenCbHandler extends MqttBaseHandler {
         }
     }
 
+    @Override
+    public int getObjType() {
+        return DevObjType.DEVC.getCode();
+    }
+
     /**
-     * 刷新设备状态
+     * 据根据累计量更新电量计量数
      *
-     * @param device 设备信息
+     * @param device  设备信息
+     * @param msgBody 消息体
      */
-    private void refreshStatus(EmsDevice device) {
-        device.setDeviceStatus(1);
-        deviceService.updateEmsDevice(device);
+    private void syncElecMeterByCumulant(EmsDevice device, JSONObject msgBody) {
+        MeterDevice meterDev = meterDeviceService.selectMeterDeviceByCode(device.getDeviceCode());
+
+        if (null == meterDev) {
+            return;
+        }
+
+        Map<String, String> arrtMap = attrCache.get(device.getDeviceCode());
+
+        // 获取当前时间
+        String currentTime = DateUtils.dateToString(new Date(), "yyyy-MM-dd HH:00:00");
+        LocalDateTime currentLdt = LocalDateTime.parse(currentTime, TIME_FORMATTER);
+        // 获取缓存时间
+        String cacheTime = arrtMap.get("elecMeterHour");
+
+        if (StringUtils.isNotEmpty(cacheTime)) {
+            LocalDateTime cacheLdt = LocalDateTime.parse(cacheTime, TIME_FORMATTER);
+
+            String newEngValue = msgBody.getString("energy");
+
+            long hours = ChronoUnit.HOURS.between(cacheLdt, currentLdt);
+
+            if (hours == 1) {
+                String lastEngValue = arrtMap.get("elecMeterHourValue");
+
+                BigDecimal lastEngValueBig = new BigDecimal(lastEngValue);
+                BigDecimal newEngValueBig = new BigDecimal(newEngValue);
+                BigDecimal diff = newEngValueBig.subtract(lastEngValueBig);
+
+                Date date = DateUtils.stringToDate(cacheTime, "yyyy-MM-dd HH:mm:ss");
+
+                ElecMeterH elecMeterH = new ElecMeterH();
+                elecMeterH.setAreaCode(meterDev.getAreaCode());
+                elecMeterH.setDeviceCode(meterDev.getDeviceCode());
+                elecMeterH.setRecordTime(date);
+                elecMeterH.setDate(date);
+                elecMeterH.setTime(date);
+                elecMeterH.setTimeIndex(getHourIndex(date));
+                elecMeterH.setElecQuantity(diff.doubleValue());
+
+                Price price = priceService.getElecHourPrice(meterDev.getAreaCode(), date);
+
+                if (null != price) {
+                    BigDecimal cost = diff.multiply(new BigDecimal(String.valueOf(price.getPriceValue())));
+                    elecMeterH.setMeterType(price.getMeterType());
+                    elecMeterH.setMeterUnitPrice(price.getPriceValue());
+                    elecMeterH.setUseElecCost(cost.doubleValue());
+                }
+
+                elecMeterHService.insertElecMeterH(elecMeterH);
+                LocalDateTime nextTime = cacheLdt.plusHours(1);
+                String nextHour = nextTime.format(TIME_FORMATTER);
+                arrtMap.put("elecMeterHour", nextHour);
+                arrtMap.put("elecMeterHourValue", newEngValue);
+            }
+            else if (hours == 0) {
+                arrtMap.computeIfAbsent("elecMeterHourValue", key -> newEngValue);
+            }
+            else if (hours > 1) {
+                LocalDateTime nextTime = currentLdt.plusHours(1);
+                String nextHour = nextTime.format(TIME_FORMATTER);
+                arrtMap.put("elecMeterHour", nextHour);
+                arrtMap.remove("elecMeterHourValue");
+            }
+        }
+        else {
+            LocalDateTime nextTime = currentLdt.plusHours(1);
+            String nextHour = nextTime.format(TIME_FORMATTER);
+            arrtMap.put("elecMeterHour", nextHour);
+        }
     }
 
     /**
@@ -190,25 +263,25 @@ public class GeekOpenCbHandler extends MqttBaseHandler {
      * @param jsonBody jsonBody 消息体
      */
     private void updateBaseAttr(EmsDevice device, JSONObject jsonBody) {
-        checkForUpdate(device, jsonBody, "key");
-        checkForUpdate(device, jsonBody, "iccid");
-        checkForUpdate(device, jsonBody, "imei");
-        checkForUpdate(device, jsonBody, "signal");
-        checkForUpdate(device, jsonBody, "version");
-        checkForUpdate(device, jsonBody, "timerEnable");
-        checkForUpdate(device, jsonBody, "timerInterval");
-        checkForUpdate(device, jsonBody, "keyLock");
-        checkForUpdate(device, jsonBody, "onState");
-        checkForUpdate(device, jsonBody, "resetLock");
+        updateAttr(device, jsonBody, "key");
+        updateAttr(device, jsonBody, "iccid");
+        updateAttr(device, jsonBody, "imei");
+        updateAttr(device, jsonBody, "signal");
+        updateAttr(device, jsonBody, "version");
+        updateAttr(device, jsonBody, "timerEnable");
+        updateAttr(device, jsonBody, "timerInterval");
+        updateAttr(device, jsonBody, "keyLock");
+        updateAttr(device, jsonBody, "onState");
+        updateAttr(device, jsonBody, "resetLock");
 
         // 协议信息
-        checkForUpdate(device, jsonBody, "protocol");
-        checkForUpdate(device, jsonBody, "clientId");
-        checkForUpdate(device, jsonBody, "server");
-        checkForUpdate(device, jsonBody, "port");
-        checkForUpdate(device, jsonBody, "username");
-        checkForUpdate(device, jsonBody, "publish");
-        checkForUpdate(device, jsonBody, "subcribe");
+        updateAttr(device, jsonBody, "protocol");
+        updateAttr(device, jsonBody, "clientId");
+        updateAttr(device, jsonBody, "server");
+        updateAttr(device, jsonBody, "port");
+        updateAttr(device, jsonBody, "username");
+        updateAttr(device, jsonBody, "publish");
+        updateAttr(device, jsonBody, "subcribe");
     }
 
     /**
@@ -218,53 +291,13 @@ public class GeekOpenCbHandler extends MqttBaseHandler {
      * @param jsonBody jsonBody 消息体
      */
     private void updateAutoAttr(EmsDevice device, JSONObject jsonBody) {
-        checkForUpdate(device, jsonBody, "voltage");
-        checkForUpdate(device, jsonBody, "current");
-        checkForUpdate(device, jsonBody, "power");
-        checkForUpdate(device, jsonBody, "energy");
-    }
+        updateAttr(device, jsonBody, "voltage");
+        updateAttr(device, jsonBody, "current");
+        updateAttr(device, jsonBody, "power");
 
-    /**
-     * 校验是否需要更新属性值
-     *
-     * @param jsonBody jsonBody 消息体
-     * @param attrKey  属性key
-     * @return true 更新,false 不更新
-     */
-    private void checkForUpdate(EmsDevice device, JSONObject jsonBody, String attrKey) {
-        if (!jsonBody.containsKey(attrKey)) {
-            return;
+        if (updateAttr(device, jsonBody, "energy")) {
+            syncElecMeterByCumulant(device, jsonBody);
         }
-        String currentValue = jsonBody.getString(attrKey);
-
-        // Atomically initialize the cache entry if absent
-        Map<String, String> attrMap = attrCache.computeIfAbsent(device.getDeviceCode(), k -> {
-            List<EmsObjAttrValue> attrList = objAttrValueService.selectByObjCode(DEVICE_OBJ_TYPE, k);
-            if (CollectionUtils.isNotEmpty(attrList)) {
-                return attrList.stream().collect(
-                    Collectors.toMap(EmsObjAttrValue::getAttrKey, EmsObjAttrValue::getAttrValue, (v1, v2) -> v1,
-                        ConcurrentHashMap::new));
-            }
-            else {
-                return new ConcurrentHashMap<>();
-            }
-        });
-
-        String cachedValue = attrMap.get(attrKey);
-
-        if (!StringUtils.equals(currentValue, cachedValue)) {
-            EmsObjAttrValue attrValue = new EmsObjAttrValue(device.getDeviceCode(), DEVICE_OBJ_TYPE,
-                device.getDeviceModel(), attrKey, currentValue);
-            objAttrValueService.mergeObjAttrValue(attrValue);
-            updateCacheAfterSuccess(device, attrKey, currentValue);
-        }
-    }
-
-    public void updateCacheAfterSuccess(EmsDevice device, String attrKey, String newValue) {
-        attrCache.computeIfPresent(device.getDeviceCode(), (k, attrMap) -> {
-            attrMap.put(attrKey, newValue);
-            return attrMap;
-        });
     }
 
     private boolean checkResult(JSONObject sendObject, JSONObject receiveObject) {

+ 179 - 6
ems/ems-cloud/ems-dev-adapter/src/main/java/com/ruoyi/ems/handle/MqttBaseHandler.java

@@ -11,8 +11,30 @@
 package com.ruoyi.ems.handle;
 
 import com.alibaba.fastjson2.JSONObject;
+import com.huashe.common.utils.DateUtils;
+import com.ruoyi.ems.core.MqttTemplate;
+import com.ruoyi.ems.domain.EmsDevice;
+import com.ruoyi.ems.domain.EmsObjAttrValue;
+import com.ruoyi.ems.enums.DevOnlineStatus;
 import com.ruoyi.ems.model.AbilityPayload;
-import com.ruoyi.ems.util.IdUtils;
+import com.ruoyi.ems.service.IEmsDeviceService;
+import com.ruoyi.ems.service.IEmsObjAttrValueService;
+import org.apache.commons.collections4.CollectionUtils;
+import org.apache.commons.lang3.StringUtils;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.beans.factory.annotation.Qualifier;
+import org.springframework.scheduling.annotation.Scheduled;
+
+import javax.annotation.Resource;
+import java.util.Calendar;
+import java.util.Date;
+import java.util.Iterator;
+import java.util.List;
+import java.util.Map;
+import java.util.concurrent.ConcurrentHashMap;
+import java.util.stream.Collectors;
 
 /**
  * Mqtt基类
@@ -25,6 +47,31 @@ import com.ruoyi.ems.util.IdUtils;
  */
 public abstract class MqttBaseHandler {
     /**
+     * 日志服务
+     */
+    protected static final Logger log = LoggerFactory.getLogger(MqttBaseHandler.class);
+
+    /**
+     * 缓存设备属性
+     */
+    protected static final Map<String, Map<String, String>> attrCache = new ConcurrentHashMap<>();
+
+    /**
+     * 最后一次消息时间缓存key
+     */
+    protected static final String MQTT_LAST_TIME = "mqttLastMsgTime";
+
+    @Resource
+    @Qualifier("mqttTemplate")
+    protected MqttTemplate mqttTemplate;
+
+    @Autowired
+    protected IEmsDeviceService deviceService;
+
+    @Autowired
+    protected IEmsObjAttrValueService objAttrValueService;
+
+    /**
      * 抽象方法,用于能力调用
      *
      * @param abilityParam 能力参数
@@ -42,13 +89,11 @@ public abstract class MqttBaseHandler {
     public abstract void msgHandle(String deviceCode, String payload);
 
     /**
-     * 默认-生成消息ID
+     * 获取设备对象类型
      *
-     * @return String 消息ID
+     * @return 设备对象类型字符串
      */
-    public String newMsgId() {
-        return IdUtils.generateMessageId();
-    }
+    public abstract int getObjType();
 
     /**
      * 添加消息ID到消息中
@@ -61,4 +106,132 @@ public abstract class MqttBaseHandler {
         json.put(msgIdKey, msgIdValue);
         return json.toString();
     }
+
+    public void sendMqttMsg(String topic, String payload, int qos, boolean retained) {
+        log.info("[Send] Topic:{}, message:{}, qos:{}, retained:{}", topic, payload, qos, retained);
+        mqttTemplate.send(topic, payload, 2, false);
+    }
+
+    /**
+     * 校验是否需要更新属性值
+     *
+     * @param jsonBody jsonBody 消息体
+     * @param attrKey  属性key
+     * @return true 更新,false 不更新
+     */
+    public boolean updateAttr(EmsDevice device, JSONObject jsonBody, String attrKey) {
+        boolean flag = false;
+
+        try {
+            // 校验消息体是否包含属性key
+            if (!jsonBody.containsKey(attrKey)) {
+                return flag;
+            }
+
+            // 获取属性值
+            String currentValue = jsonBody.getString(attrKey);
+
+            // 获取缓存
+            Map<String, String> attrMap = attrCache.computeIfAbsent(device.getDeviceCode(), k -> {
+                List<EmsObjAttrValue> attrList = objAttrValueService.selectByObjCode(getObjType(), k);
+
+                if (CollectionUtils.isNotEmpty(attrList)) {
+                    return attrList.stream().collect(
+                        Collectors.toMap(EmsObjAttrValue::getAttrKey, EmsObjAttrValue::getAttrValue, (v1, v2) -> v1,
+                            ConcurrentHashMap::new));
+                }
+                else {
+                    return new ConcurrentHashMap<>();
+                }
+            });
+
+            // 从缓存中获取属性值
+            String cacheValue = attrMap.get(attrKey);
+
+            // 比较属性值是否发生变化
+            if (!StringUtils.equals(currentValue, cacheValue)) {
+                EmsObjAttrValue attrValue = new EmsObjAttrValue(device.getDeviceCode(), getObjType(),
+                    device.getDeviceModel(), attrKey, currentValue);
+                // 更新数据库
+                objAttrValueService.mergeObjAttrValue(attrValue);
+                // 更新缓存
+                updateCacheAfterSuccess(device, attrKey, currentValue);
+
+                flag = true;
+            }
+        }
+        catch (Exception e) {
+            log.error("检查属性并更新失败!", e);
+        }
+
+        return flag;
+    }
+
+    public void updateMsgTime(EmsDevice device, Date timeValue) {
+        try {
+            String dateTime = DateUtils.dateToString(timeValue, DateUtils.YYYY_MM_DD_HH_MM_SS);
+
+            attrCache.computeIfAbsent(device.getDeviceCode(), k -> new ConcurrentHashMap<>());
+
+            // 更新缓存
+            updateCacheAfterSuccess(device, MQTT_LAST_TIME, dateTime);
+        }
+        catch (Exception e) {
+            log.error("刷新缓存消息时间失败!", e);
+        }
+    }
+
+    public void updateCacheAfterSuccess(EmsDevice device, String attrKey, String newValue) {
+        attrCache.computeIfPresent(device.getDeviceCode(), (k, attrMap) -> {
+            attrMap.put(attrKey, newValue);
+            return attrMap;
+        });
+    }
+
+    /**
+     * 刷新设备状态
+     *
+     * @param device 设备信息
+     */
+    public void refreshStatus(EmsDevice device, DevOnlineStatus status) {
+        if (device.getDeviceStatus() != status.getCode()) {
+            device.setDeviceStatus(status.getCode());
+            deviceService.updateEmsDevice(device);
+            log.info("设备[{}]{}...", device.getDeviceCode(), status == DevOnlineStatus.ONLINE ? "上线" : "下线");
+        }
+    }
+
+    protected static int getHourIndex(Date date) {
+        Calendar calendar =  Calendar.getInstance();
+        calendar.setTime(date);
+        int hour = calendar.get(Calendar.HOUR_OF_DAY);
+        return hour + 1;
+    }
+
+    /**
+     * 定时检测在线状态
+     * <br/>每小时执行一次,扫描2个小时无消息的设备,标记为离线状态
+     */
+    @Scheduled(cron = "0 5 0/1 * * ?")
+    public void checkOnlineStatus() {
+        long currentTime = new Date().getTime();
+        long threshold = 2 * 60 * 60 * 1000; // 120分钟
+
+        Iterator<Map.Entry<String, Map<String, String>>> iterator = attrCache.entrySet().iterator();
+        while (iterator.hasNext()) {
+            Map.Entry<String, Map<String, String>> entry = iterator.next();
+            String deviceCode = entry.getKey();
+            Map<String, String> msg = entry.getValue();
+
+            String lastMsgTime = msg.get(MQTT_LAST_TIME);
+
+            if (StringUtils.isNotEmpty(lastMsgTime)) {
+                Date lastMsgTimeDt = DateUtils.stringToDate(lastMsgTime, DateUtils.YYYY_MM_DD_HH_MM_SS);
+                if ((currentTime - lastMsgTimeDt.getTime()) > threshold) {
+                    EmsDevice device = deviceService.selectByCode(deviceCode);
+                    refreshStatus(device, DevOnlineStatus.OFFLINE);
+                }
+            }
+        }
+    }
 }

+ 1 - 1
ems/ems-cloud/ems-dev-adapter/src/main/java/com/ruoyi/ems/handle/RootMsgHandler.java

@@ -37,7 +37,7 @@ public class RootMsgHandler implements MqttMessageHandler {
     @Override
     public void handle(String topic, String payload) {
         try {
-            log.info("[Receive]Topic:{}, message:{}", topic, payload);
+            log.info("[Receive] Topic:{}, message:{}", topic, payload);
 
             if (StringUtils.startsWith(topic, "/server/dlq/")) {
                 String deviceCode = StringUtils.substringAfter(topic, "/server/dlq/");

+ 1 - 1
ems/ems-cloud/ems-dev-adapter/src/main/resources/application-local.yml

@@ -46,7 +46,7 @@ spring:
 mqtt:
   server:
     host: tcp://xt.wenhq.top:8581
-    client_id: mqtt_dev_adapter
+    client_id: lear-Dev
   executor:
     msgHandle:
       corePoolSize: 20

+ 13 - 13
ems/ems-cloud/ems-server/src/main/java/com/ruoyi/ems/controller/ElecPriceController.java

@@ -44,7 +44,7 @@ public class ElecPriceController extends BaseController {
     @GetMapping("/gw/list")
     public TableDataInfo listGw(ElecGwPriceConfig elecValencyConfig) {
         startPage();
-        List<ElecGwPriceConfig> list = configService.selectGwElecPriceConfigList(elecValencyConfig);
+        List<ElecGwPriceConfig> list = configService.selectGwElecPriceCfgList(elecValencyConfig);
         return getDataTable(list);
     }
 
@@ -55,7 +55,7 @@ public class ElecPriceController extends BaseController {
     @Log(title = "国网电价配置", businessType = BusinessType.EXPORT)
     @PostMapping("/gw/export")
     public void exportGw(HttpServletResponse response, ElecGwPriceConfig elecValencyConfig) {
-        List<ElecGwPriceConfig> list = configService.selectGwElecPriceConfigList(elecValencyConfig);
+        List<ElecGwPriceConfig> list = configService.selectGwElecPriceCfgList(elecValencyConfig);
         ExcelUtil<ElecGwPriceConfig> util = new ExcelUtil<>(ElecGwPriceConfig.class);
         util.exportExcel(response, list, "国网电价配置数据");
     }
@@ -66,7 +66,7 @@ public class ElecPriceController extends BaseController {
     @RequiresPermissions("basecfg:price:query")
     @GetMapping(value = "/gw/{id}")
     public AjaxResult getGwInfo(@PathVariable("id") Long id) {
-        return success(configService.selectGwElecPriceConfigById(id));
+        return success(configService.selectGwElecPriceCfgById(id));
     }
 
     /**
@@ -76,7 +76,7 @@ public class ElecPriceController extends BaseController {
     @Log(title = "电价配置", businessType = BusinessType.INSERT)
     @PostMapping(value = "/gw")
     public AjaxResult addGw(@RequestBody ElecGwPriceConfig elecValencyConfig) {
-        return toAjax(configService.insertGwElecPriceConfig(elecValencyConfig));
+        return toAjax(configService.insertGwElecPriceCfg(elecValencyConfig));
     }
 
     /**
@@ -86,7 +86,7 @@ public class ElecPriceController extends BaseController {
     @Log(title = "电价配置", businessType = BusinessType.UPDATE)
     @PutMapping(value = "/gw")
     public AjaxResult editGw(@RequestBody ElecGwPriceConfig elecValencyConfig) {
-        return toAjax(configService.updateGwElecPriceConfig(elecValencyConfig));
+        return toAjax(configService.updateGwElecPriceCfg(elecValencyConfig));
     }
 
     /**
@@ -96,7 +96,7 @@ public class ElecPriceController extends BaseController {
     @Log(title = "电价配置", businessType = BusinessType.DELETE)
     @DeleteMapping("/gw/{ids}")
     public AjaxResult removeGw(@PathVariable Long[] ids) {
-        return toAjax(configService.deleteGwElecPriceConfigByIds(ids));
+        return toAjax(configService.deleteGwElecPriceCfgByIds(ids));
     }
 
     /**
@@ -105,7 +105,7 @@ public class ElecPriceController extends BaseController {
      */
     @GetMapping("/gw/listall")
     public AjaxResult listAllGw() {
-        List<ElecGwPriceConfig> list = configService.selectGwElecPriceConfigList(new ElecGwPriceConfig());
+        List<ElecGwPriceConfig> list = configService.selectGwElecPriceCfgList(new ElecGwPriceConfig());
         return success(list);
     }
 
@@ -117,7 +117,7 @@ public class ElecPriceController extends BaseController {
     public TableDataInfo listPv(ElecPvPriceConfig pvPriceConfig)
     {
         startPage();
-        List<ElecPvPriceConfig> list = configService.selectPvPriceConfigList(pvPriceConfig);
+        List<ElecPvPriceConfig> list = configService.selectPvPriceCfgList(pvPriceConfig);
         return getDataTable(list);
     }
 
@@ -129,7 +129,7 @@ public class ElecPriceController extends BaseController {
     @PostMapping("/pv/export")
     public void exportPv(HttpServletResponse response, ElecPvPriceConfig pvPriceConfig)
     {
-        List<ElecPvPriceConfig> list = configService.selectPvPriceConfigList(pvPriceConfig);
+        List<ElecPvPriceConfig> list = configService.selectPvPriceCfgList(pvPriceConfig);
         ExcelUtil<ElecPvPriceConfig> util = new ExcelUtil<>(ElecPvPriceConfig.class);
         util.exportExcel(response, list, "光伏电价配置数据");
     }
@@ -141,7 +141,7 @@ public class ElecPriceController extends BaseController {
     @GetMapping(value = "/pv/{id}")
     public AjaxResult getPvInfo(@PathVariable("id") Long id)
     {
-        return success(configService.selectPvPriceConfigById(id));
+        return success(configService.selectPvPriceCfgById(id));
     }
 
     /**
@@ -152,7 +152,7 @@ public class ElecPriceController extends BaseController {
     @PostMapping(value = "/pv")
     public AjaxResult addPv(@RequestBody ElecPvPriceConfig pvPriceConfig)
     {
-        return toAjax(configService.insertPvPriceConfig(pvPriceConfig));
+        return toAjax(configService.insertPvPriceCfg(pvPriceConfig));
     }
 
     /**
@@ -163,7 +163,7 @@ public class ElecPriceController extends BaseController {
     @PutMapping(value = "/pv")
     public AjaxResult editPv(@RequestBody ElecPvPriceConfig pvPriceConfig)
     {
-        return toAjax(configService.updatePvPriceConfig(pvPriceConfig));
+        return toAjax(configService.updatePvPriceCfg(pvPriceConfig));
     }
 
     /**
@@ -174,6 +174,6 @@ public class ElecPriceController extends BaseController {
     @DeleteMapping("/pv/{ids}")
     public AjaxResult removePv(@PathVariable Long[] ids)
     {
-        return toAjax(configService.deletePvPriceConfigByIds(ids));
+        return toAjax(configService.deletePvPriceCfgByIds(ids));
     }
 }

+ 1 - 2
ems/ems-cloud/ems-server/src/main/java/com/ruoyi/ems/controller/MeterReadingController.java

@@ -129,8 +129,7 @@ public class MeterReadingController extends BaseController {
     }
 
     private void fillData(MeterReading lastItem, MeterReading meterRec) {
-        MeterDevice meterDevice = meterDeviceService.selectMeterDeviceByCode(meterRec.getAreaCode(),
-            meterRec.getDeviceCode());
+        MeterDevice meterDevice = meterDeviceService.selectMeterDeviceByCode(meterRec.getDeviceCode());
         Date date = new Date();
 
         if (null != lastItem) {

+ 3 - 3
ems/ems-core/src/main/java/com/ruoyi/ems/domain/ElecPriceStrategy.java

@@ -41,7 +41,7 @@ public class ElecPriceStrategy extends BaseEntity
 
     /** 优先级 */
     @Excel(name = "优先级")
-    private Long priority;
+    private Integer priority;
 
     /** 编辑标记 */
     private Integer editFlag = 1;
@@ -96,11 +96,11 @@ public class ElecPriceStrategy extends BaseEntity
         this.repeatParam = repeatParam;
     }
 
-    public Long getPriority() {
+    public Integer getPriority() {
         return priority;
     }
 
-    public void setPriority(Long priority) {
+    public void setPriority(Integer priority) {
         this.priority = priority;
     }
 

+ 3 - 3
ems/ems-core/src/main/java/com/ruoyi/ems/domain/ElecPriceStrategyHour.java

@@ -37,7 +37,7 @@ public class ElecPriceStrategyHour extends BaseEntity
 
     /** 计量类型 */
     @Excel(name = "计量类型")
-    private Long type;
+    private Integer type;
 
     public void setId(Long id) 
     {
@@ -74,12 +74,12 @@ public class ElecPriceStrategyHour extends BaseEntity
         this.endTime = endTime;
     }
 
-    public void setType(Long type)
+    public void setType(Integer type)
     {
         this.type = type;
     }
 
-    public Long getType() 
+    public Integer getType()
     {
         return type;
     }

+ 35 - 0
ems/ems-core/src/main/java/com/ruoyi/ems/enums/DevOnlineStatus.java

@@ -0,0 +1,35 @@
+/*
+ * 文 件 名:  DevOnOffStatus
+ * 版    权:  华设设计集团股份有限公司
+ * 描    述:  <描述>
+ * 修 改 人:  lvwenbin
+ * 修改时间:  2025/3/6
+ * 跟踪单号:  <跟踪单号>
+ * 修改单号:  <修改单号>
+ * 修改内容:  <修改内容>
+ */
+package com.ruoyi.ems.enums;
+
+/**
+ * 设备在线状态枚举类
+ * <功能详细描述>
+ *
+ * @author lvwenbin
+ * @version [版本号, 2025/3/6]
+ * @see [相关类/方法]
+ * @since [产品/模块版本]
+ */
+public enum DevOnlineStatus {
+    ONLINE(1),
+    OFFLINE(0);
+
+    private int code;
+
+    DevOnlineStatus(int code) {
+        this.code = code;
+    }
+
+    public int getCode() {
+        return code;
+    }
+}

+ 9 - 0
ems/ems-core/src/main/java/com/ruoyi/ems/mapper/ElecGwPriceConfigMapper.java

@@ -1,6 +1,7 @@
 package com.ruoyi.ems.mapper;
 
 import com.ruoyi.ems.domain.ElecGwPriceConfig;
+import org.apache.ibatis.annotations.Param;
 
 import java.util.List;
 
@@ -20,6 +21,14 @@ public interface ElecGwPriceConfigMapper {
     ElecGwPriceConfig selectElecPriceConfigById(Long id);
 
     /**
+     * 查询电价配置
+     *
+     * @param cfgCode 电价配置主键
+     * @return 电价配置
+     */
+    ElecGwPriceConfig selectElecPriceConfigByCode(@Param("cfgCode") String cfgCode);
+
+    /**
      * 查询电价配置列表
      *
      * @param elecPriceConfig 电价配置

+ 2 - 2
ems/ems-core/src/main/java/com/ruoyi/ems/mapper/MeterDeviceMapper.java

@@ -23,11 +23,11 @@ public interface MeterDeviceMapper {
     /**
      * 查询计量设备
      *
-     * @param areaCode   区域code
+
      * @param deviceCode 设备code
      * @return 计量设备
      */
-    MeterDevice selectMeterDeviceByCode(@Param("areaCode") String areaCode, @Param("deviceCode") String deviceCode);
+    MeterDevice selectMeterDeviceByCode(@Param("deviceCode") String deviceCode);
 
     List<MeterDevice> selectMeterDeviceByObj(@Param("areaCode") String areaCode, @Param("objType") int objType,
         @Param("boundaryObj") String boundaryObj, @Param("meterCls") int meterCls);

+ 84 - 0
ems/ems-core/src/main/java/com/ruoyi/ems/model/Price.java

@@ -0,0 +1,84 @@
+/*
+ * 文 件 名:  Price
+ * 版    权:  华设设计集团股份有限公司
+ * 描    述:  <描述>
+ * 修 改 人:  lvwenbin
+ * 修改时间:  2025/3/11
+ * 跟踪单号:  <跟踪单号>
+ * 修改单号:  <修改单号>
+ * 修改内容:  <修改内容>
+ */
+package com.ruoyi.ems.model;
+
+/**
+ * 价格实体
+ * <功能详细描述>
+ *
+ * @author lvwenbin
+ * @version [版本号, 2025/3/11]
+ * @see [相关类/方法]
+ * @since [产品/模块版本]
+ */
+public class Price {
+    /**
+     * 价格编码(adm_gw_elecprice_config.cfg_code)
+     */
+    private String priceCode;
+
+    /**
+     * 策略编码(adm_elecprice_strategy.strategy_code)
+     */
+    private String strategyCode;
+
+    /**
+     * 价格策略类型
+     */
+    private int meterType;
+
+    /**
+     * 价格值
+     */
+    private Double priceValue;
+
+    public Price() {
+    }
+
+    public Price(String priceCode, String strategyCode, int meterType, Double priceValue) {
+        this.priceCode = priceCode;
+        this.strategyCode = strategyCode;
+        this.meterType = meterType;
+        this.priceValue = priceValue;
+    }
+
+    public String getPriceCode() {
+        return priceCode;
+    }
+
+    public void setPriceCode(String priceCode) {
+        this.priceCode = priceCode;
+    }
+
+    public String getStrategyCode() {
+        return strategyCode;
+    }
+
+    public void setStrategyCode(String strategyCode) {
+        this.strategyCode = strategyCode;
+    }
+
+    public int getMeterType() {
+        return meterType;
+    }
+
+    public void setMeterType(int meterType) {
+        this.meterType = meterType;
+    }
+
+    public Double getPriceValue() {
+        return priceValue;
+    }
+
+    public void setPriceValue(Double priceValue) {
+        this.priceValue = priceValue;
+    }
+}

+ 20 - 12
ems/ems-core/src/main/java/com/ruoyi/ems/service/IElecPriceConfigService.java

@@ -18,7 +18,15 @@ public interface IElecPriceConfigService {
      * @param id 电价配置主键
      * @return 电价配置
      */
-    ElecGwPriceConfig selectGwElecPriceConfigById(Long id);
+    ElecGwPriceConfig selectGwElecPriceCfgById(Long id);
+
+    /**
+     * 查询电价配置
+     *
+     * @param code 电价配置code
+     * @return 电价配置
+     */
+    ElecGwPriceConfig selectGwElecPriceCfgByCode(String code);
 
     /**
      * 查询电价配置列表
@@ -26,7 +34,7 @@ public interface IElecPriceConfigService {
      * @param elecPriceConfig 电价配置
      * @return 电价配置集合
      */
-    List<ElecGwPriceConfig> selectGwElecPriceConfigList(ElecGwPriceConfig elecPriceConfig);
+    List<ElecGwPriceConfig> selectGwElecPriceCfgList(ElecGwPriceConfig elecPriceConfig);
 
     /**
      * 新增电价配置
@@ -34,7 +42,7 @@ public interface IElecPriceConfigService {
      * @param elecPriceConfig 电价配置
      * @return 结果
      */
-    int insertGwElecPriceConfig(ElecGwPriceConfig elecPriceConfig);
+    int insertGwElecPriceCfg(ElecGwPriceConfig elecPriceConfig);
 
     /**
      * 修改电价配置
@@ -42,7 +50,7 @@ public interface IElecPriceConfigService {
      * @param elecPriceConfig 电价配置
      * @return 结果
      */
-    int updateGwElecPriceConfig(ElecGwPriceConfig elecPriceConfig);
+    int updateGwElecPriceCfg(ElecGwPriceConfig elecPriceConfig);
 
     /**
      * 批量删除电价配置
@@ -50,7 +58,7 @@ public interface IElecPriceConfigService {
      * @param ids 需要删除的电价配置主键集合
      * @return 结果
      */
-    int deleteGwElecPriceConfigByIds(Long[] ids);
+    int deleteGwElecPriceCfgByIds(Long[] ids);
 
     /**
      * 删除电价配置信息
@@ -58,7 +66,7 @@ public interface IElecPriceConfigService {
      * @param id 电价配置主键
      * @return 结果
      */
-    int deleteGwElecPriceConfigById(Long id);
+    int deleteGwElecPriceCfgById(Long id);
 
     /**
      * 查询光伏电价配置
@@ -66,7 +74,7 @@ public interface IElecPriceConfigService {
      * @param id 光伏电价配置主键
      * @return 光伏电价配置
      */
-    ElecPvPriceConfig selectPvPriceConfigById(Long id);
+    ElecPvPriceConfig selectPvPriceCfgById(Long id);
 
     /**
      * 查询光伏电价配置列表
@@ -74,7 +82,7 @@ public interface IElecPriceConfigService {
      * @param elecPvPriceConfig 光伏电价配置
      * @return 光伏电价配置集合
      */
-    List<ElecPvPriceConfig> selectPvPriceConfigList(ElecPvPriceConfig elecPvPriceConfig);
+    List<ElecPvPriceConfig> selectPvPriceCfgList(ElecPvPriceConfig elecPvPriceConfig);
 
     /**
      * 新增光伏电价配置
@@ -82,7 +90,7 @@ public interface IElecPriceConfigService {
      * @param elecPvPriceConfig 光伏电价配置
      * @return 结果
      */
-    int insertPvPriceConfig(ElecPvPriceConfig elecPvPriceConfig);
+    int insertPvPriceCfg(ElecPvPriceConfig elecPvPriceConfig);
 
     /**
      * 修改光伏电价配置
@@ -90,7 +98,7 @@ public interface IElecPriceConfigService {
      * @param elecPvPriceConfig 光伏电价配置
      * @return 结果
      */
-    int updatePvPriceConfig(ElecPvPriceConfig elecPvPriceConfig);
+    int updatePvPriceCfg(ElecPvPriceConfig elecPvPriceConfig);
 
     /**
      * 批量删除光伏电价配置
@@ -98,7 +106,7 @@ public interface IElecPriceConfigService {
      * @param ids 需要删除的光伏电价配置主键集合
      * @return 结果
      */
-    int deletePvPriceConfigByIds(Long[] ids);
+    int deletePvPriceCfgByIds(Long[] ids);
 
     /**
      * 删除光伏电价配置信息
@@ -106,5 +114,5 @@ public interface IElecPriceConfigService {
      * @param id 光伏电价配置主键
      * @return 结果
      */
-    int deletePvPriceConfigById(Long id);
+    int deletePvPriceCfgById(Long id);
 }

+ 1 - 2
ems/ems-core/src/main/java/com/ruoyi/ems/service/IMeterDeviceService.java

@@ -23,11 +23,10 @@ public interface IMeterDeviceService {
     /**
      * 查询计量设备
      *
-     * @param areaCode   区域code
      * @param deviceCode 设备code
      * @return 计量设备
      */
-    MeterDevice selectMeterDeviceByCode(String areaCode, String deviceCode);
+    MeterDevice selectMeterDeviceByCode(String deviceCode);
 
     /**
      * 查询计量设备列表

+ 34 - 0
ems/ems-core/src/main/java/com/ruoyi/ems/service/IPriceService.java

@@ -0,0 +1,34 @@
+/*
+ * 文 件 名:  IPriceService
+ * 版    权:  华设设计集团股份有限公司
+ * 描    述:  <描述>
+ * 修 改 人:  lvwenbin
+ * 修改时间:  2025/3/10
+ * 跟踪单号:  <跟踪单号>
+ * 修改单号:  <修改单号>
+ * 修改内容:  <修改内容>
+ */
+package com.ruoyi.ems.service;
+
+import com.ruoyi.ems.model.Price;
+
+import java.util.Date;
+
+/**
+ * 价格服务
+ * <功能详细描述>
+ *
+ * @author lvwenbin
+ * @version [版本号, 2025/3/10]
+ * @see [相关类/方法]
+ * @since [产品/模块版本]
+ */
+public interface IPriceService {
+    /**
+     * 获取小时电价
+     * @param areaCode 地区编码
+     * @param date 日期
+     * @return 价格
+     */
+    Price getElecHourPrice(String areaCode, Date date);
+}

+ 17 - 12
ems/ems-core/src/main/java/com/ruoyi/ems/service/impl/ElecPriceConfigServiceImpl.java

@@ -31,10 +31,15 @@ public class ElecPriceConfigServiceImpl implements IElecPriceConfigService {
      * @return 电价配置
      */
     @Override
-    public ElecGwPriceConfig selectGwElecPriceConfigById(Long id) {
+    public ElecGwPriceConfig selectGwElecPriceCfgById(Long id) {
         return gwPriceConfigMapper.selectElecPriceConfigById(id);
     }
 
+    @Override
+    public ElecGwPriceConfig selectGwElecPriceCfgByCode(String code) {
+        return gwPriceConfigMapper.selectElecPriceConfigByCode(code);
+    }
+
     /**
      * 查询电价配置列表
      *
@@ -42,7 +47,7 @@ public class ElecPriceConfigServiceImpl implements IElecPriceConfigService {
      * @return 电价配置
      */
     @Override
-    public List<ElecGwPriceConfig> selectGwElecPriceConfigList(ElecGwPriceConfig elecPriceConfig) {
+    public List<ElecGwPriceConfig> selectGwElecPriceCfgList(ElecGwPriceConfig elecPriceConfig) {
         return gwPriceConfigMapper.selectElecPriceConfigList(elecPriceConfig);
     }
 
@@ -53,7 +58,7 @@ public class ElecPriceConfigServiceImpl implements IElecPriceConfigService {
      * @return 结果
      */
     @Override
-    public int insertGwElecPriceConfig(ElecGwPriceConfig elecPriceConfig) {
+    public int insertGwElecPriceCfg(ElecGwPriceConfig elecPriceConfig) {
         return gwPriceConfigMapper.insertElecPriceConfig(elecPriceConfig);
     }
 
@@ -64,7 +69,7 @@ public class ElecPriceConfigServiceImpl implements IElecPriceConfigService {
      * @return 结果
      */
     @Override
-    public int updateGwElecPriceConfig(ElecGwPriceConfig elecPriceConfig) {
+    public int updateGwElecPriceCfg(ElecGwPriceConfig elecPriceConfig) {
         return gwPriceConfigMapper.updateElecPriceConfig(elecPriceConfig);
     }
 
@@ -75,7 +80,7 @@ public class ElecPriceConfigServiceImpl implements IElecPriceConfigService {
      * @return 结果
      */
     @Override
-    public int deleteGwElecPriceConfigByIds(Long[] ids) {
+    public int deleteGwElecPriceCfgByIds(Long[] ids) {
         return gwPriceConfigMapper.deleteElecPriceConfigByIds(ids);
     }
 
@@ -86,7 +91,7 @@ public class ElecPriceConfigServiceImpl implements IElecPriceConfigService {
      * @return 结果
      */
     @Override
-    public int deleteGwElecPriceConfigById(Long id) {
+    public int deleteGwElecPriceCfgById(Long id) {
         return gwPriceConfigMapper.deleteElecPriceConfigById(id);
     }
 
@@ -97,7 +102,7 @@ public class ElecPriceConfigServiceImpl implements IElecPriceConfigService {
      * @return 光伏电价配置
      */
     @Override
-    public ElecPvPriceConfig selectPvPriceConfigById(Long id) {
+    public ElecPvPriceConfig selectPvPriceCfgById(Long id) {
         return pvPriceConfigMapper.selectPvPriceConfigById(id);
     }
 
@@ -108,7 +113,7 @@ public class ElecPriceConfigServiceImpl implements IElecPriceConfigService {
      * @return 光伏电价配置
      */
     @Override
-    public List<ElecPvPriceConfig> selectPvPriceConfigList(ElecPvPriceConfig elecPvPriceConfig) {
+    public List<ElecPvPriceConfig> selectPvPriceCfgList(ElecPvPriceConfig elecPvPriceConfig) {
         return pvPriceConfigMapper.selectPvPriceConfigList(elecPvPriceConfig);
     }
 
@@ -119,7 +124,7 @@ public class ElecPriceConfigServiceImpl implements IElecPriceConfigService {
      * @return 结果
      */
     @Override
-    public int insertPvPriceConfig(ElecPvPriceConfig elecPvPriceConfig) {
+    public int insertPvPriceCfg(ElecPvPriceConfig elecPvPriceConfig) {
         return pvPriceConfigMapper.insertPvPriceConfig(elecPvPriceConfig);
     }
 
@@ -130,7 +135,7 @@ public class ElecPriceConfigServiceImpl implements IElecPriceConfigService {
      * @return 结果
      */
     @Override
-    public int updatePvPriceConfig(ElecPvPriceConfig elecPvPriceConfig) {
+    public int updatePvPriceCfg(ElecPvPriceConfig elecPvPriceConfig) {
         return pvPriceConfigMapper.updatePvPriceConfig(elecPvPriceConfig);
     }
 
@@ -141,7 +146,7 @@ public class ElecPriceConfigServiceImpl implements IElecPriceConfigService {
      * @return 结果
      */
     @Override
-    public int deletePvPriceConfigByIds(Long[] ids) {
+    public int deletePvPriceCfgByIds(Long[] ids) {
         return pvPriceConfigMapper.deletePvPriceConfigByIds(ids);
     }
 
@@ -152,7 +157,7 @@ public class ElecPriceConfigServiceImpl implements IElecPriceConfigService {
      * @return 结果
      */
     @Override
-    public int deletePvPriceConfigById(Long id) {
+    public int deletePvPriceCfgById(Long id) {
         return pvPriceConfigMapper.deletePvPriceConfigById(id);
     }
 }

+ 0 - 1
ems/ems-core/src/main/java/com/ruoyi/ems/service/impl/EmsObjAbilityCallLogServiceImpl.java

@@ -3,7 +3,6 @@ package com.ruoyi.ems.service.impl;
 import com.ruoyi.ems.domain.EmsObjAbilityCallLog;
 import com.ruoyi.ems.mapper.EmsObjAbilityCallLogMapper;
 import com.ruoyi.ems.service.IEmsObjAbilityCallLogService;
-import org.springframework.beans.factory.annotation.Autowired;
 import org.springframework.stereotype.Service;
 
 import javax.annotation.Resource;

+ 2 - 2
ems/ems-core/src/main/java/com/ruoyi/ems/service/impl/MeterDeviceServiceImpl.java

@@ -32,8 +32,8 @@ public class MeterDeviceServiceImpl implements IMeterDeviceService {
     }
 
     @Override
-    public MeterDevice selectMeterDeviceByCode(String areaCode, String deviceCode) {
-        return meterDeviceMapper.selectMeterDeviceByCode(areaCode, deviceCode);
+    public MeterDevice selectMeterDeviceByCode(String deviceCode) {
+        return meterDeviceMapper.selectMeterDeviceByCode(deviceCode);
     }
 
     /**

+ 169 - 0
ems/ems-core/src/main/java/com/ruoyi/ems/service/impl/PriceServiceImpl.java

@@ -0,0 +1,169 @@
+/*
+ * 文 件 名:  PriceServiceImpl
+ * 版    权:  华设设计集团股份有限公司
+ * 描    述:  <描述>
+ * 修 改 人:  lvwenbin
+ * 修改时间:  2025/3/10
+ * 跟踪单号:  <跟踪单号>
+ * 修改单号:  <修改单号>
+ * 修改内容:  <修改内容>
+ */
+package com.ruoyi.ems.service.impl;
+
+import com.huashe.common.exception.Assert;
+import com.huashe.common.exception.BusinessException;
+import com.huashe.common.utils.DateUtils;
+import com.ruoyi.ems.domain.ElecAttr;
+import com.ruoyi.ems.domain.ElecGwPriceConfig;
+import com.ruoyi.ems.domain.ElecPriceStrategy;
+import com.ruoyi.ems.domain.ElecPriceStrategyHour;
+import com.ruoyi.ems.model.Price;
+import com.ruoyi.ems.service.IElecAttrService;
+import com.ruoyi.ems.service.IElecPriceConfigService;
+import com.ruoyi.ems.service.IElecPriceStrategyService;
+import com.ruoyi.ems.service.IPriceService;
+import org.apache.commons.lang3.ArrayUtils;
+import org.apache.commons.lang3.StringUtils;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.stereotype.Service;
+
+import java.util.Calendar;
+import java.util.Date;
+import java.util.List;
+
+/**
+ * 价格服务
+ * <功能详细描述>
+ *
+ * @author lvwenbin
+ * @version [版本号, 2025/3/10]
+ * @see [相关类/方法]
+ * @since [产品/模块版本]
+ */
+@Service
+public class PriceServiceImpl implements IPriceService {
+    private static final Logger log = LoggerFactory.getLogger(PriceServiceImpl.class);
+
+    /**
+     * 服务区用电属性服务
+     */
+    @Autowired
+    private IElecAttrService elecAttrService;
+
+    /**
+     * 国网电价服务
+     */
+    @Autowired
+    private IElecPriceConfigService elecPriceConfigService;
+
+    /**
+     * 电价策略
+     */
+    @Autowired
+    private IElecPriceStrategyService elecPriceStrategyService;
+
+    @Override
+    public Price getElecHourPrice(String areaCode, Date date) {
+        Price price = null;
+
+        try {
+            ElecAttr elecAttr = elecAttrService.getEffectiveByArea(areaCode);
+            Assert.notNull(elecAttr, -1, "未查询到有效的用电属性信息");
+
+            String priceCode = elecAttr.getPriceCode();
+            Assert.notEmpty(priceCode, -1, "未配置电价策略");
+            ElecGwPriceConfig priceConfig = elecPriceConfigService.selectGwElecPriceCfgByCode(priceCode);
+
+            List<ElecPriceStrategy> strategyList = elecPriceStrategyService.selectList(new ElecPriceStrategy());
+            strategyList.sort((o1, o2) -> o2.getPriority() - o1.getPriority());
+            String time = DateUtils.dateToString(date, "HH:mm:ss");
+
+            for (ElecPriceStrategy strategy : strategyList) {
+                if (!dateMatch(strategy, date)) {
+                    continue;
+                }
+
+                List<ElecPriceStrategyHour> hourList = strategy.getHourList();
+
+                Integer hourType = getStrategyHourType(hourList, time);
+
+                if (null != hourType) {
+                    price = getPrice(hourType, priceCode, strategy.getStrategyCode(), priceConfig);
+                    break;
+                }
+            }
+        }
+        catch (BusinessException e) {
+            log.warn("获取电价失败,原因:{}", e.getMessage());
+        }
+        catch (Exception e) {
+            log.error("获取电价失败", e);
+        }
+
+        return price;
+    }
+
+    private Price getPrice(Integer hourType, String priceCode, String strategyCode, ElecGwPriceConfig priceConfig) {
+        Price price = null;
+
+        switch (hourType) {
+            case -1:
+                price = new Price(priceCode, strategyCode, hourType, priceConfig.getFsLowDegreePrice());
+                break;
+            case 1:
+                price = new Price(priceCode, strategyCode, hourType, priceConfig.getFsHighDegreePrice());
+                break;
+            case 2:
+                price = new Price(priceCode, strategyCode, hourType, priceConfig.getFsPeakDegreePrice());
+                break;
+            default:
+                price = new Price(priceCode, strategyCode, hourType, priceConfig.getFsFlatDegreePrice());
+                break;
+        }
+
+        return price;
+    }
+
+    private Integer getStrategyHourType(List<ElecPriceStrategyHour> hourList, String time) {
+        Integer hourType = null;
+
+        for (ElecPriceStrategyHour hourCfg : hourList) {
+            if (time.compareTo(hourCfg.getStartTime().toString()) >= 0
+                && time.compareTo(hourCfg.getEndTime().toString()) <= 0) {
+                hourType = hourCfg.getType();
+                break;
+            }
+        }
+
+        return hourType;
+    }
+
+    /**
+     * 日期匹配重复规则
+     *
+     * @param strategy 策略
+     * @param date     日期
+     * @return 匹配结果
+     */
+    private boolean dateMatch(ElecPriceStrategy strategy, Date date) {
+        boolean flag = false;
+
+        if (strategy.getRepeatType() == 1 || strategy.getRepeatType() == 3 || strategy.getRepeatType() == 4) {
+            throw new UnsupportedOperationException("不支持的日期重复类型");
+        }
+        else if (strategy.getRepeatType() == 2) {
+            flag = true;
+        }
+        else if (strategy.getRepeatType() == 5 || strategy.getRepeatType() == 6) {
+            Calendar calendar = Calendar.getInstance();
+            calendar.setTime(date);
+            int dayOfWeek = calendar.get(Calendar.DAY_OF_WEEK) - 1;
+            String[] array = StringUtils.split(strategy.getRepeatParam(), ",");
+            flag = ArrayUtils.contains(array, String.valueOf(dayOfWeek));
+        }
+
+        return flag;
+    }
+}

+ 5 - 8
ems/ems-core/src/main/resources/mapper/ems/ElecGwPriceConfigMapper.xml

@@ -31,14 +31,6 @@ PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
         <where>  
             <if test="cfgCode != null  and cfgCode != ''"> and v.cfg_code = #{cfgCode}</if>
             <if test="elecType != null "> and v.elec_type = #{elecType}</if>
-            <if test="voltageLevel != null  and voltageLevel != ''"> and v.voltage_level = #{voltageLevel}</if>
-            <if test="degreePrice != null "> and v.degree_price = #{degreePrice}</if>
-            <if test="fsPeakDegreePrice != null "> and v.fs_peak_degree_price = #{fsPeakDegreePrice}</if>
-            <if test="fsHighDegreePrice != null "> and v.fs_high_degree_price = #{fsHighDegreePrice}</if>
-            <if test="fsFlatDegreePrice != null "> and v.fs_flat_degree_price = #{fsFlatDegreePrice}</if>
-            <if test="fsLowDegreePrice != null "> and v.fs_low_degree_price = #{fsLowDegreePrice}</if>
-            <if test="maxReqPrice != null "> and v.max_req_price = #{maxReqPrice}</if>
-            <if test="transCapacityPrice != null "> and v.trans_capacity_price = #{transCapacityPrice}</if>
         </where>
     </select>
     
@@ -46,6 +38,11 @@ PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
         <include refid="selectElecPriceConfigVo"/>
         where v.id = #{id}
     </select>
+
+    <select id="selectElecPriceConfigByCode" parameterType="java.lang.String" resultMap="elecPriceConfigResult">
+        <include refid="selectElecPriceConfigVo"/>
+        where v.cfg_code = #{cfgCode}
+    </select>
         
     <insert id="insertElecPriceConfig" parameterType="com.ruoyi.ems.domain.ElecGwPriceConfig" useGeneratedKeys="true" keyProperty="id">
         insert into adm_gw_elecprice_config

+ 1 - 1
ems/ems-core/src/main/resources/mapper/ems/MeterDeviceMapper.xml

@@ -42,7 +42,7 @@ PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
 
     <select id="selectMeterDeviceByCode"  resultMap="meterDeviceResult">
         <include refid="selectMeterDeviceVo"/>
-        where area_code = #{areaCode} and device_code = #{deviceCode}
+        where device_code = #{deviceCode}
     </select>
 
     <select id="selectMeterDeviceByObj"  resultMap="meterDeviceResult">