From fd15e6f7dd6a2f6bccf27a8b06fc60211e7df28e Mon Sep 17 00:00:00 2001
From: puzhibing <393733352@qq.com>
Date: 星期一, 28 九月 2026 09:05:49 +0800
Subject: [PATCH] Merge branch '2.3' of http://120.76.84.145:10101/gitblit/r/java/mx_charging_pile into 2.3
---
ruoyi-service/ruoyi-other/src/main/java/com/ruoyi/other/emind/service/EmindEnergyChainManagementService.java | 28 ++
ruoyi-service/ruoyi-other/src/main/java/com/ruoyi/other/udan/model/ElectricMeterState.java | 32 +++
ruoyi-service/ruoyi-other/src/main/java/com/ruoyi/other/udan/model/UdanEmsDeviceState.java | 5
ruoyi-service/ruoyi-other/src/main/resources/sql/t_screen_content_alter.sql | 26 ++
ruoyi-service/ruoyi-other/src/main/resources/mapper/other/EmindStationMapper.xml | 4
ruoyi-service/ruoyi-other/src/main/resources/mapper/other/EmindStorageDashboardMapper.xml | 5
ruoyi-service/ruoyi-other/src/main/java/com/ruoyi/other/emind/service/EmindEnergyChainSyncService.java | 8
ruoyi-service/ruoyi-other/src/main/java/com/ruoyi/other/service/impl/TStationCollectServiceImpl.java | 7
ruoyi-service/ruoyi-other/src/main/java/com/ruoyi/other/udan/service/UdanEmsMessageProcessor.java | 140 +++++++++++++
ruoyi-service/ruoyi-other/src/main/resources/mapper/other/EmindEnergyChainMapper.xml | 3
ruoyi-service/ruoyi-other/src/main/java/com/ruoyi/other/emind/domain/EmindEnergyChain.java | 9
ruoyi-service/ruoyi-other/src/main/java/com/ruoyi/other/emind/mapper/EmindStorageDashboardMapper.java | 3
ruoyi-service/ruoyi-other/src/main/java/com/ruoyi/other/task/ExchangeCodeExpireTask.java | 2
ruoyi-service/ruoyi-other/src/main/java/com/ruoyi/other/emind/service/EmindEnergyChainDetailService.java | 111 +++++++++++
ruoyi-service/ruoyi-other/src/main/java/com/ruoyi/other/udan/model/TmsState.java | 35 +++
ruoyi-service/ruoyi-other/src/main/java/com/ruoyi/other/udan/model/PcsState.java | 59 +++++
ruoyi-service/ruoyi-other/src/main/java/com/ruoyi/other/emind/domain/EmindEnergyChainDetail.java | 56 +++++
ruoyi-service/ruoyi-other/src/main/java/com/ruoyi/other/emind/service/EmindStationManagementService.java | 2
ruoyi-service/ruoyi-other/src/main/java/com/ruoyi/other/udan/model/BatteryStackState.java | 39 +++
ruoyi-service/ruoyi-other/src/main/java/com/ruoyi/other/emind/mapper/EmindEnergyChainDetailMapper.java | 8
20 files changed, 565 insertions(+), 17 deletions(-)
diff --git a/ruoyi-service/ruoyi-other/src/main/java/com/ruoyi/other/emind/domain/EmindEnergyChain.java b/ruoyi-service/ruoyi-other/src/main/java/com/ruoyi/other/emind/domain/EmindEnergyChain.java
index 0a4776f..8bb892a 100644
--- a/ruoyi-service/ruoyi-other/src/main/java/com/ruoyi/other/emind/domain/EmindEnergyChain.java
+++ b/ruoyi-service/ruoyi-other/src/main/java/com/ruoyi/other/emind/domain/EmindEnergyChain.java
@@ -125,4 +125,13 @@
/** Data status, not persisted. */
@ApiModelProperty("Data status, not persisted")
private Integer dataStatus;
+
+ /**
+ * 设备类型(平台为华为时展示)
+ */
+ @TableField("station_type")
+ private String stationType;
+
+ @TableField(exist = false)
+ private String detail;
}
diff --git a/ruoyi-service/ruoyi-other/src/main/java/com/ruoyi/other/emind/domain/EmindEnergyChainDetail.java b/ruoyi-service/ruoyi-other/src/main/java/com/ruoyi/other/emind/domain/EmindEnergyChainDetail.java
new file mode 100644
index 0000000..713e606
--- /dev/null
+++ b/ruoyi-service/ruoyi-other/src/main/java/com/ruoyi/other/emind/domain/EmindEnergyChainDetail.java
@@ -0,0 +1,56 @@
+package com.ruoyi.other.emind.domain;
+
+import com.baomidou.mybatisplus.annotation.IdType;
+import com.baomidou.mybatisplus.annotation.TableField;
+import com.baomidou.mybatisplus.annotation.TableId;
+import com.baomidou.mybatisplus.annotation.TableName;
+import io.swagger.annotations.ApiModel;
+import io.swagger.annotations.ApiModelProperty;
+import lombok.Data;
+
+import java.time.LocalDateTime;
+
+/** eMind 储能能量链本地冗余数据。 */
+@Data
+@ApiModel("EmindEnergyChainDetail")
+@TableName("t_emind_energy_chain_detail")
+public class EmindEnergyChainDetail {
+
+
+ @TableId(value = "id", type = IdType.AUTO)
+ @ApiModelProperty("Primary key")
+ private Long id;
+
+ @TableField("platform_name")
+ private String platformName;
+
+ @TableField("station_id")
+ private String stationId;
+
+ @TableField("station_code")
+ private String stationCode;
+
+ @TableField("station_type")
+ private String stationType;
+
+ @TableField("detail")
+ private String detail;
+
+ @TableField("data_source")
+ @ApiModelProperty("Data source: 1 remote, 2 manual")
+ private Integer dataSource;
+
+ @TableField("del_flag")
+ private Integer delFlag;
+
+ @TableField("sync_time")
+ private LocalDateTime syncTime;
+
+ @TableField("create_time")
+ private LocalDateTime createTime;
+
+ @TableField("update_time")
+ private LocalDateTime updateTime;
+
+
+}
diff --git a/ruoyi-service/ruoyi-other/src/main/java/com/ruoyi/other/emind/mapper/EmindEnergyChainDetailMapper.java b/ruoyi-service/ruoyi-other/src/main/java/com/ruoyi/other/emind/mapper/EmindEnergyChainDetailMapper.java
new file mode 100644
index 0000000..b5d2bc0
--- /dev/null
+++ b/ruoyi-service/ruoyi-other/src/main/java/com/ruoyi/other/emind/mapper/EmindEnergyChainDetailMapper.java
@@ -0,0 +1,8 @@
+package com.ruoyi.other.emind.mapper;
+
+import com.baomidou.mybatisplus.core.mapper.BaseMapper;
+import com.ruoyi.other.emind.domain.EmindEnergyChainDetail;
+
+/** 能量链详情数据访问层。 */
+public interface EmindEnergyChainDetailMapper extends BaseMapper<EmindEnergyChainDetail> {
+}
diff --git a/ruoyi-service/ruoyi-other/src/main/java/com/ruoyi/other/emind/mapper/EmindStorageDashboardMapper.java b/ruoyi-service/ruoyi-other/src/main/java/com/ruoyi/other/emind/mapper/EmindStorageDashboardMapper.java
index b8d88b8..aeba6b2 100644
--- a/ruoyi-service/ruoyi-other/src/main/java/com/ruoyi/other/emind/mapper/EmindStorageDashboardMapper.java
+++ b/ruoyi-service/ruoyi-other/src/main/java/com/ruoyi/other/emind/mapper/EmindStorageDashboardMapper.java
@@ -9,6 +9,7 @@
import java.math.BigDecimal;
import java.util.List;
import java.util.Map;
+import java.util.Set;
public interface EmindStorageDashboardMapper {
int upsertSnapshot(@Param("station") EmindStation station, @Param("data") EmindMainTotalDto data,
@@ -27,4 +28,6 @@
@Param("endDate") LocalDate endDate);
List<Map<String, Object>> selectCurveRows(@Param("stationId") Long stationId, @Param("platformNames") List<String> platformNames);
List<Map<String, Object>> selectEnergyBlockRows(@Param("stationId") Long stationId, @Param("platformNames") List<String> platformNames);
+
+ void deleteByStationIdDay(@Param("stationId") Long stationId, @Param("dateSet") Set<LocalDate> dateSet);
}
diff --git a/ruoyi-service/ruoyi-other/src/main/java/com/ruoyi/other/emind/service/EmindEnergyChainDetailService.java b/ruoyi-service/ruoyi-other/src/main/java/com/ruoyi/other/emind/service/EmindEnergyChainDetailService.java
new file mode 100644
index 0000000..2574abf
--- /dev/null
+++ b/ruoyi-service/ruoyi-other/src/main/java/com/ruoyi/other/emind/service/EmindEnergyChainDetailService.java
@@ -0,0 +1,111 @@
+package com.ruoyi.other.emind.service;
+
+import com.alibaba.fastjson2.JSON;
+import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
+import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
+import com.ruoyi.other.emind.domain.EmindEnergyChainDetail;
+import com.ruoyi.other.emind.mapper.EmindEnergyChainDetailMapper;
+import com.ruoyi.other.udan.model.UdanEmsDeviceState;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.stereotype.Service;
+import org.springframework.transaction.annotation.Transactional;
+
+import java.time.Clock;
+import java.time.LocalDateTime;
+import java.util.ArrayList;
+import java.util.List;
+import java.util.Objects;
+
+/** 能量链详情服务。 */
+@Service
+public class EmindEnergyChainDetailService {
+ private final EmindEnergyChainDetailMapper mapper;
+ private final Clock clock;
+
+ @Autowired
+ public EmindEnergyChainDetailService(EmindEnergyChainDetailMapper mapper) {
+ this(mapper, Clock.systemDefaultZone());
+ }
+
+ EmindEnergyChainDetailService(EmindEnergyChainDetailMapper mapper, Clock clock) {
+ this.mapper = mapper;
+ this.clock = clock;
+ }
+
+ /** 新增能量链详情。 */
+ @Transactional(rollbackFor = Exception.class)
+ public EmindEnergyChainDetail add(EmindEnergyChainDetail input) {
+ LocalDateTime now = LocalDateTime.now(clock);
+ EmindEnergyChainDetail detail = new EmindEnergyChainDetail();
+ detail.setPlatformName(input.getPlatformName());
+ detail.setStationId(input.getStationId());
+ detail.setStationCode(input.getStationCode());
+ detail.setStationType(input.getStationType());
+ detail.setDetail(input.getDetail());
+ detail.setDataSource(input.getDataSource());
+ detail.setDelFlag(0);
+ detail.setSyncTime(now);
+ detail.setCreateTime(now);
+ detail.setUpdateTime(now);
+ mapper.insert(detail);
+ return detail;
+ }
+
+ /** 根据设备类型和设备编号查询有效的能量链详情。 */
+ public List<EmindEnergyChainDetail> getByStationTypes(List<String> stationTypes) {
+ return mapper.selectList(new LambdaQueryWrapper<EmindEnergyChainDetail>()
+ .eq(EmindEnergyChainDetail::getDelFlag, 0)
+ .in(EmindEnergyChainDetail::getStationType, stationTypes));
+ }
+
+ @Transactional
+ public void saveAll(UdanEmsDeviceState udanEmsDeviceState) {
+ List<EmindEnergyChainDetail> detailList = new ArrayList<>();
+ // 保存BMS
+ if(Objects.nonNull(udanEmsDeviceState.getTmsState())) {
+ EmindEnergyChainDetail detail = new EmindEnergyChainDetail();
+ detail.setPlatformName("欧力特");
+ detail.setDataSource(2);
+ detail.setStationCode(udanEmsDeviceState.getEmsSystemId());
+ detail.setDetail(JSON.toJSONString(udanEmsDeviceState.getTmsState()));
+ detail.setStationId(udanEmsDeviceState.getTmsState().getDeviceId());
+ detail.setStationType("TMS");
+ detailList.add(detail);
+ }
+ if(Objects.nonNull(udanEmsDeviceState.getPcsState())) {
+ EmindEnergyChainDetail detail = new EmindEnergyChainDetail();
+ detail.setPlatformName("欧力特");
+ detail.setDataSource(2);
+ detail.setStationCode(udanEmsDeviceState.getEmsSystemId());
+ detail.setDetail(JSON.toJSONString(udanEmsDeviceState.getPcsState()));
+ detail.setStationId(udanEmsDeviceState.getTmsState().getDeviceId());
+ detail.setStationType("PCS");
+ detailList.add(detail);
+ }
+ if(Objects.nonNull(udanEmsDeviceState.getElectricMeterState())) {
+ EmindEnergyChainDetail detail = new EmindEnergyChainDetail();
+ detail.setPlatformName("欧力特");
+ detail.setDataSource(2);
+ detail.setStationCode(udanEmsDeviceState.getEmsSystemId());
+ detail.setDetail(JSON.toJSONString(udanEmsDeviceState.getElectricMeterState()));
+ detail.setStationId(udanEmsDeviceState.getTmsState().getDeviceId());
+ detail.setStationType("电表");
+ detailList.add(detail);
+ }
+ if(Objects.nonNull(udanEmsDeviceState.getBatteryStackState())) {
+ EmindEnergyChainDetail detail = new EmindEnergyChainDetail();
+ detail.setPlatformName("欧力特");
+ detail.setDataSource(2);
+ detail.setStationCode(udanEmsDeviceState.getEmsSystemId());
+ detail.setDetail(JSON.toJSONString(udanEmsDeviceState.getBatteryStackState()));
+ detail.setStationId(udanEmsDeviceState.getTmsState().getDeviceId());
+ detail.setStationType("BMS");
+ detailList.add(detail);
+ }
+ detailList.forEach(d -> {
+ mapper.delete(new QueryWrapper<EmindEnergyChainDetail>().eq("station_code", d.getStationCode()).eq("station_type", d.getStationType()));
+ add(d);
+ });
+
+ }
+}
diff --git a/ruoyi-service/ruoyi-other/src/main/java/com/ruoyi/other/emind/service/EmindEnergyChainManagementService.java b/ruoyi-service/ruoyi-other/src/main/java/com/ruoyi/other/emind/service/EmindEnergyChainManagementService.java
index 0299a0a..20fe6af 100644
--- a/ruoyi-service/ruoyi-other/src/main/java/com/ruoyi/other/emind/service/EmindEnergyChainManagementService.java
+++ b/ruoyi-service/ruoyi-other/src/main/java/com/ruoyi/other/emind/service/EmindEnergyChainManagementService.java
@@ -3,10 +3,12 @@
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.ruoyi.other.emind.domain.EmindEnergyChain;
+import com.ruoyi.other.emind.domain.EmindEnergyChainDetail;
import com.ruoyi.other.emind.domain.EmindStation;
import com.ruoyi.other.emind.dto.EmindEnergyChainPageQuery;
import com.ruoyi.other.emind.mapper.EmindEnergyChainMapper;
import com.ruoyi.other.emind.mapper.EmindStationMapper;
+import org.apache.commons.collections4.CollectionUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
@@ -14,32 +16,49 @@
import java.time.Clock;
import java.time.LocalDateTime;
import java.util.List;
+import java.util.stream.Collectors;
@Service
public class EmindEnergyChainManagementService {
private final EmindEnergyChainMapper mapper;
private final EmindStationMapper stationMapper;
private final Clock clock;
+ private final EmindEnergyChainDetailService emindEnergyChainDetailService;
@Autowired
public EmindEnergyChainManagementService(EmindEnergyChainMapper mapper,
- EmindStationMapper stationMapper) {
- this(mapper, stationMapper, Clock.systemDefaultZone());
+ EmindStationMapper stationMapper, EmindEnergyChainDetailService emindEnergyChainDetailService) {
+ this(mapper, stationMapper, Clock.systemDefaultZone(), emindEnergyChainDetailService);
}
EmindEnergyChainManagementService(EmindEnergyChainMapper mapper,
EmindStationMapper stationMapper,
- Clock clock) {
+ Clock clock, EmindEnergyChainDetailService emindEnergyChainDetailService) {
this.mapper = mapper;
this.stationMapper = stationMapper;
this.clock = clock;
+ this.emindEnergyChainDetailService = emindEnergyChainDetailService;
}
public IPage<EmindEnergyChain> page(EmindEnergyChainPageQuery query) {
int pageNumber = query.getPageCurr() == null || query.getPageCurr() < 1 ? 1 : query.getPageCurr();
int pageSize = query.getPageSize() == null || query.getPageSize() < 1
? 10 : Math.min(query.getPageSize(), 100);
- return mapper.selectManagementPage(Page.of(pageNumber, pageSize), query);
+ IPage<EmindEnergyChain> pageData = mapper.selectManagementPage(Page.of(pageNumber, pageSize), query);
+ if(CollectionUtils.isNotEmpty(pageData.getRecords())) {
+ List<String> stationTypeList = pageData.getRecords().stream().filter(r -> "欧力特".equals(r.getPlatformName())).map(EmindEnergyChain::getStationType).collect(Collectors.toList());
+ if(CollectionUtils.isNotEmpty(stationTypeList)) {
+ List<EmindEnergyChainDetail> chainDetails = emindEnergyChainDetailService.getByStationTypes(stationTypeList);
+ if(CollectionUtils.isNotEmpty(chainDetails)) {
+ pageData.getRecords().forEach(rd -> chainDetails.forEach(cd -> {
+ if(cd.getStationType().equals(rd.getStationType())) {
+ rd.setDetail(cd.getDetail());
+ }
+ }));
+ }
+ }
+ }
+ return pageData;
}
@Transactional(rollbackFor = Exception.class)
@@ -97,5 +116,6 @@
target.setElinkId(input.getElinkId());
target.setUuid(input.getUuid().trim());
target.setElinkName(input.getElinkName().trim());
+ target.setStationType(input.getStationType());
}
}
diff --git a/ruoyi-service/ruoyi-other/src/main/java/com/ruoyi/other/emind/service/EmindEnergyChainSyncService.java b/ruoyi-service/ruoyi-other/src/main/java/com/ruoyi/other/emind/service/EmindEnergyChainSyncService.java
index 32f18d4..a4a9680 100644
--- a/ruoyi-service/ruoyi-other/src/main/java/com/ruoyi/other/emind/service/EmindEnergyChainSyncService.java
+++ b/ruoyi-service/ruoyi-other/src/main/java/com/ruoyi/other/emind/service/EmindEnergyChainSyncService.java
@@ -49,9 +49,11 @@
LocalDateTime syncedAt = LocalDateTime.now(clock);
List<EmindEnergyChain> chains = new ArrayList<>();
for (EmindStation station : stations) {
- List<EmindEnergyChainDto> remoteChains = api.getEnergyChains(station.getStationId());
- for (EmindEnergyChainDto remote : remoteChains) {
- chains.add(toEntity(station, remote, syncedAt));
+ if(station.getSourceType() == 1) {
+ List<EmindEnergyChainDto> remoteChains = api.getEnergyChains(station.getStationId());
+ for (EmindEnergyChainDto remote : remoteChains) {
+ chains.add(toEntity(station, remote, syncedAt));
+ }
}
}
chainMapper.markAllDeleted(syncedAt);
diff --git a/ruoyi-service/ruoyi-other/src/main/java/com/ruoyi/other/emind/service/EmindStationManagementService.java b/ruoyi-service/ruoyi-other/src/main/java/com/ruoyi/other/emind/service/EmindStationManagementService.java
index 95f124e..db846e3 100644
--- a/ruoyi-service/ruoyi-other/src/main/java/com/ruoyi/other/emind/service/EmindStationManagementService.java
+++ b/ruoyi-service/ruoyi-other/src/main/java/com/ruoyi/other/emind/service/EmindStationManagementService.java
@@ -38,7 +38,7 @@
public EmindStation add(EmindStation input) {
LocalDateTime now = LocalDateTime.now(clock);
EmindStation station = new EmindStation();
- station.setStationId(input.getStationId() == null ? -System.currentTimeMillis() : input.getStationId());
+ station.setStationId(input.getStationId() == null ? System.currentTimeMillis() : input.getStationId());
station.setName(input.getName());
station.setAddress(input.getAddress());
station.setProvince(input.getProvince());
diff --git a/ruoyi-service/ruoyi-other/src/main/java/com/ruoyi/other/service/impl/TStationCollectServiceImpl.java b/ruoyi-service/ruoyi-other/src/main/java/com/ruoyi/other/service/impl/TStationCollectServiceImpl.java
index 541eb91..d4ef6ca 100644
--- a/ruoyi-service/ruoyi-other/src/main/java/com/ruoyi/other/service/impl/TStationCollectServiceImpl.java
+++ b/ruoyi-service/ruoyi-other/src/main/java/com/ruoyi/other/service/impl/TStationCollectServiceImpl.java
@@ -349,6 +349,13 @@
fillDefaults(collect);
insertList.add(collect);
}
+ // 设置电站名称
+ List<TStationInfo> infoList = stationInfoMapper.selectList(new LambdaQueryWrapper<>());
+ insertList.forEach(s -> infoList.forEach(info -> {
+ if(StringUtils.isNotEmpty(s.getStationId()) && s.getStationId().equals(info.getStationId())) {
+ s.setStationName(info.getStationName());
+ }
+ }));
return CollectionUtils.isNotEmpty(insertList) && saveBatch(insertList);
}
}
diff --git a/ruoyi-service/ruoyi-other/src/main/java/com/ruoyi/other/task/ExchangeCodeExpireTask.java b/ruoyi-service/ruoyi-other/src/main/java/com/ruoyi/other/task/ExchangeCodeExpireTask.java
index 437a87f..1f978fa 100644
--- a/ruoyi-service/ruoyi-other/src/main/java/com/ruoyi/other/task/ExchangeCodeExpireTask.java
+++ b/ruoyi-service/ruoyi-other/src/main/java/com/ruoyi/other/task/ExchangeCodeExpireTask.java
@@ -30,7 +30,7 @@
}
/**
- * 每6小时执行科士达的数据同步
+ * 每6小时执行华为光伏的数据同步
*/
@Scheduled(cron = "0 0 */6 * * ?")
public void syncHuaWeiDataTask() {
diff --git a/ruoyi-service/ruoyi-other/src/main/java/com/ruoyi/other/udan/model/BatteryStackState.java b/ruoyi-service/ruoyi-other/src/main/java/com/ruoyi/other/udan/model/BatteryStackState.java
new file mode 100644
index 0000000..964667a
--- /dev/null
+++ b/ruoyi-service/ruoyi-other/src/main/java/com/ruoyi/other/udan/model/BatteryStackState.java
@@ -0,0 +1,39 @@
+package com.ruoyi.other.udan.model;
+
+import lombok.Data;
+
+import java.io.Serializable;
+
+/**
+ * 优旦储能-BMS 实时数据
+ *
+ * @author Lux
+ * @version 1.0.0
+ * @since 2026/9/26 16:23
+ */
+@Data
+public class BatteryStackState implements Serializable {
+
+ /**
+ * 设备id
+ */
+ private String deviceId;
+
+ // 故障状态
+ private String errorStatus;
+ private String workStatus; // 工作状态
+ private String warningStatus; // 告警状态
+ private Double tv; // 总电压 单位V
+ private Double tc; // 总电流 单位A
+ private Double soh; // soh 单位%
+ private Double soc; // soc 单位%
+ private Double rechargeableCapacityKwh; // 可充电量 单位kWh
+ private Double dischargeableCapacityKwh; // 可放电量 单位kWh
+ private Double cumulativeDischargeKwh; // 累计放电量 单位kWh
+ private Double cumulativeChargeKwh; // 累计充电量 单位kWh
+ private Double minCellVoltMv; // 单体最低电压 单位mV
+ private Double maxCellVoltMv; // 单体最高电压 单位mV
+ private Double avgCellTemp; // 电芯平均温度 保存需减40偏移量
+
+
+}
diff --git a/ruoyi-service/ruoyi-other/src/main/java/com/ruoyi/other/udan/model/ElectricMeterState.java b/ruoyi-service/ruoyi-other/src/main/java/com/ruoyi/other/udan/model/ElectricMeterState.java
new file mode 100644
index 0000000..684b0af
--- /dev/null
+++ b/ruoyi-service/ruoyi-other/src/main/java/com/ruoyi/other/udan/model/ElectricMeterState.java
@@ -0,0 +1,32 @@
+package com.ruoyi.other.udan.model;
+
+import lombok.Data;
+
+import java.io.Serializable;
+
+/**
+ * 优旦储能-电表实时数据
+ *
+ * @author Lux
+ * @version 1.0.0
+ * @since 2026/9/26 16:23
+ */
+@Data
+public class ElectricMeterState implements Serializable {
+
+ /**
+ * 设备id
+ */
+ private String deviceId;
+
+ private Double aPhaseVolt; // A相电压 单位V
+ private Double bPhaseVolt; // B相电压 单位V
+ private Double cPhaseVolt; // C相电压 单位V
+ private Double aPhaseCurrent; // A相电流 单位A
+ private Double bPhaseCurrent; // B相电流 单位A
+ private Double cPhaseCurrent; // C相电流 单位A
+ private Double acTotalActivePower; // 总有功功率 单位KW
+ private Double frequency; // 频率 单位Hz
+ private Double acTotalPowerFactor; // 总交流功率因数
+
+}
diff --git a/ruoyi-service/ruoyi-other/src/main/java/com/ruoyi/other/udan/model/PcsState.java b/ruoyi-service/ruoyi-other/src/main/java/com/ruoyi/other/udan/model/PcsState.java
new file mode 100644
index 0000000..bd4dd59
--- /dev/null
+++ b/ruoyi-service/ruoyi-other/src/main/java/com/ruoyi/other/udan/model/PcsState.java
@@ -0,0 +1,59 @@
+package com.ruoyi.other.udan.model;
+
+import lombok.Data;
+
+import java.io.Serializable;
+
+/**
+ * 优旦储能-pcs实时数据
+ *
+ * @author Lux
+ * @version 1.0.0
+ * @since 2026/9/26 16:23
+ */
+@Data
+public class PcsState implements Serializable {
+
+ /**
+ * 设备id
+ */
+ private String deviceId;
+
+ // 故障状态
+ private String errorStatus;
+
+ // 告警状态
+ private String alarmStatus;
+
+ // 运行状态
+ private String runStatus;
+
+ // 并网状态
+ private String onGridStatus;
+
+ // 有功功率A相
+ private Double aPhaseActivePower;
+
+ // 有功功率B相
+ private Double bPhaseActivePower;
+
+ // 有功功率C相
+ private Double cPhaseActivePower;
+
+ // 总交流有功功率
+ private Double acTotalActivePower;
+
+ // 日充电量 单位kWh
+ private Double dailyChargeEnergyKwh;
+
+ // 日放电量 单位kWh
+ private Double dailyDischargeEnergyKwh;
+
+ // 总充电量 单位kWh
+ private Double totalChargeEnergyKwh;
+
+ // 总放电量 单位kWh
+ private Double totalDischargeEnergyKwh;
+
+
+}
diff --git a/ruoyi-service/ruoyi-other/src/main/java/com/ruoyi/other/udan/model/TmsState.java b/ruoyi-service/ruoyi-other/src/main/java/com/ruoyi/other/udan/model/TmsState.java
new file mode 100644
index 0000000..89325d7
--- /dev/null
+++ b/ruoyi-service/ruoyi-other/src/main/java/com/ruoyi/other/udan/model/TmsState.java
@@ -0,0 +1,35 @@
+package com.ruoyi.other.udan.model;
+
+import lombok.Data;
+
+import java.io.Serializable;
+
+/**
+ * 优旦储能-TNS 实时数据
+ *
+ * @author Lux
+ * @version 1.0.0
+ * @since 2026/9/26 16:23
+ */
+@Data
+public class TmsState implements Serializable {
+
+ /**
+ * 设备id
+ */
+ private String deviceId;
+
+ private String run_status; // 运行状态
+ private String error_status; // 故障状态 0 预留 1 故障 2 正常
+ private String compress_status; // 压缩机状态
+ private String compress_heat_status; // 压缩机加热带状态
+ private String electric_heat_status; // 电加热运行状态
+ private String pump_status; // 水泵状态
+ private String fan_status; // 风机运行状态
+
+ private Double supply_temp; // 供液温度
+ private Double return_temp; // 回液温度
+ private Double env_temp; // 环境温度
+ private Double backwater_press; // 回水压力 回液压力
+ private Double out_water_press; // 出水压力 供液压力
+}
diff --git a/ruoyi-service/ruoyi-other/src/main/java/com/ruoyi/other/udan/model/UdanEmsDeviceState.java b/ruoyi-service/ruoyi-other/src/main/java/com/ruoyi/other/udan/model/UdanEmsDeviceState.java
index 2119556..25b3996 100644
--- a/ruoyi-service/ruoyi-other/src/main/java/com/ruoyi/other/udan/model/UdanEmsDeviceState.java
+++ b/ruoyi-service/ruoyi-other/src/main/java/com/ruoyi/other/udan/model/UdanEmsDeviceState.java
@@ -21,6 +21,11 @@
private EmsState emsState;
private PowerMeterState powerMeterState;
+ private TmsState tmsState;
+ private PcsState pcsState;
+ private ElectricMeterState electricMeterState;
+ private BatteryStackState batteryStackState;
+
public List<EmindIncomeHistoryDto> convert(Long stationId) {
List<EmindIncomeHistoryDto> dailyList = new ArrayList<>();
diff --git a/ruoyi-service/ruoyi-other/src/main/java/com/ruoyi/other/udan/service/UdanEmsMessageProcessor.java b/ruoyi-service/ruoyi-other/src/main/java/com/ruoyi/other/udan/service/UdanEmsMessageProcessor.java
index d305f4d..08ea393 100644
--- a/ruoyi-service/ruoyi-other/src/main/java/com/ruoyi/other/udan/service/UdanEmsMessageProcessor.java
+++ b/ruoyi-service/ruoyi-other/src/main/java/com/ruoyi/other/udan/service/UdanEmsMessageProcessor.java
@@ -7,20 +7,29 @@
import com.ruoyi.other.emind.dto.EmindIncomeHistoryDto;
import com.ruoyi.other.emind.mapper.EmindStationMapper;
import com.ruoyi.other.emind.mapper.EmindStorageDashboardMapper;
+import com.ruoyi.other.emind.service.EmindEnergyChainDetailService;
import com.ruoyi.other.udan.model.EmsState;
+import com.ruoyi.other.udan.model.BatteryStackState;
+import com.ruoyi.other.udan.model.ElectricMeterState;
+import com.ruoyi.other.udan.model.PcsState;
import com.ruoyi.other.udan.model.PowerMeterState;
+import com.ruoyi.other.udan.model.TmsState;
import com.ruoyi.other.udan.model.UdanEmsDeviceState;
import com.ruoyi.other.udan.util.UdanEmsKafkaUtil;
import lombok.extern.slf4j.Slf4j;
+import org.apache.commons.collections4.CollectionUtils;
import org.apache.commons.lang3.StringUtils;
import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
import org.springframework.stereotype.Component;
import javax.annotation.PostConstruct;
import java.io.IOException;
+import java.time.LocalDate;
import java.time.LocalDateTime;
import java.util.List;
import java.util.Objects;
+import java.util.Set;
+import java.util.stream.Collectors;
/** 将 IEmsAllDeviceState 中模型已有的 EMS 和能耗计字段转换为业务对象。 */
@Slf4j
@@ -30,11 +39,13 @@
private final UdanEmsKafkaUtil kafkaUtil;
private final EmindStorageDashboardMapper dashboardMapper;
private final EmindStationMapper stationMapper;
+ private final EmindEnergyChainDetailService emindEnergyChainDetailService;
- public UdanEmsMessageProcessor(UdanEmsKafkaUtil kafkaUtil, EmindStorageDashboardMapper dashboardMapper, EmindStationMapper stationMapper) {
+ public UdanEmsMessageProcessor(UdanEmsKafkaUtil kafkaUtil, EmindStorageDashboardMapper dashboardMapper, EmindStationMapper stationMapper, EmindEnergyChainDetailService emindEnergyChainDetailService) {
this.kafkaUtil = kafkaUtil;
this.dashboardMapper = dashboardMapper;
this.stationMapper = stationMapper;
+ this.emindEnergyChainDetailService = emindEnergyChainDetailService;
}
@PostConstruct
@@ -52,10 +63,19 @@
EmindStation station = stations.stream().filter(s -> udanEmsDeviceState.getEmsDeviceId().equals(s.getStationCode())).findFirst().orElse(null);
if(Objects.nonNull(station)) {
List<EmindIncomeHistoryDto> daily = udanEmsDeviceState.convert(station.getStationId());
- dashboardMapper.upsertDaily(station.getStationId(), daily, now);
+ Set<LocalDate> dateSet = daily.stream().map(EmindIncomeHistoryDto::getDate).collect(Collectors.toSet());
+ // 删除电站下该天已存在的旧数据
+ if(CollectionUtils.isNotEmpty(dateSet)) {
+ dashboardMapper.deleteByStationIdDay(station.getStationId(), dateSet);
+ }
+ if(CollectionUtils.isNotEmpty(daily)) {
+ dashboardMapper.upsertDaily(station.getStationId(), daily, now);
+ }
}else{
- log.info("UDAN EMS数据同步错误-电站信息不存在!");
+ log.error("UDAN EMS数据同步错误-电站信息不存在!");
}
+ // 保存设备其它信息
+ emindEnergyChainDetailService.saveAll(udanEmsDeviceState);
}
} catch (IOException e) {
@@ -76,7 +96,19 @@
read(bytes, (field, type, in) -> {
if (field == 1 && type == 0) state.setTime(in.readUInt64());
else if (type == 2 && field == 2) state.setEmsState(parseEms(in.readBytes().toByteArray()));
+ else if (type == 2 && field == 4 && state.getPcsState() == null) {
+ state.setPcsState(parsePcs(in.readBytes().toByteArray()));
+ }
+ else if (type == 2 && field == 5 && state.getBatteryStackState() == null) {
+ state.setBatteryStackState(parseBatteryStack(in.readBytes().toByteArray()));
+ }
+ else if (type == 2 && field == 7 && state.getElectricMeterState() == null) {
+ state.setElectricMeterState(parseElectricMeter(in.readBytes().toByteArray()));
+ }
else if (type == 2 && field == 8) state.setPowerMeterState(parsePowerMeter(in.readBytes().toByteArray()));
+ else if (type == 2 && field == 14 && state.getTmsState() == null) {
+ state.setTmsState(parseTms(in.readBytes().toByteArray()));
+ }
else skip(in, type);
});
return state;
@@ -189,6 +221,96 @@
return value;
}
+ private PcsState parsePcs(byte[] bytes) throws IOException {
+ PcsState value = new PcsState();
+ read(bytes, (field, type, input) -> {
+ switch (field) {
+ case 2: value.setDeviceId(str(input, type)); break;
+ case 3: value.setErrorStatus(enumName(input, type, "ErrorStatus")); break;
+ case 4: value.setAlarmStatus(enumName(input, type, "AlarmStatus")); break;
+ case 5: value.setRunStatus(enumName(input, type, "RunStatus")); break;
+ case 6: value.setOnGridStatus(enumName(input, type, "GridStatus")); break;
+ case 13: value.setAcTotalActivePower((double) f32(input, type)); break;
+ case 17: value.setDailyChargeEnergyKwh((double) f32(input, type)); break;
+ case 18: value.setDailyDischargeEnergyKwh((double) f32(input, type)); break;
+ case 19: value.setTotalChargeEnergyKwh(f64(input, type)); break;
+ case 20: value.setTotalDischargeEnergyKwh(f64(input, type)); break;
+ case 31: value.setAPhaseActivePower((double) f32(input, type)); break;
+ case 34: value.setBPhaseActivePower((double) f32(input, type)); break;
+ case 37: value.setCPhaseActivePower((double) f32(input, type)); break;
+ default: skip(input, type);
+ }
+ });
+ return value;
+ }
+
+ private BatteryStackState parseBatteryStack(byte[] bytes) throws IOException {
+ BatteryStackState value = new BatteryStackState();
+ read(bytes, (field, type, input) -> {
+ switch (field) {
+ case 2: value.setDeviceId(str(input, type)); break;
+ case 4: value.setWorkStatus(enumName(input, type, "BatteryWorkStatus")); break;
+ case 5: value.setErrorStatus(enumName(input, type, "ErrorStatus")); break;
+ case 6: value.setWarningStatus(enumName(input, type, "AlarmStatus")); break;
+ case 7: value.setTv((double) f32(input, type)); break;
+ case 8: value.setTc((double) f32(input, type)); break;
+ case 9: value.setSoh((double) f32(input, type)); break;
+ case 10: value.setSoc((double) f32(input, type)); break;
+ case 15: value.setMinCellVoltMv((double) u32(input, type)); break;
+ case 23: value.setMaxCellVoltMv((double) u32(input, type)); break;
+ case 31: value.setRechargeableCapacityKwh((double) f32(input, type)); break;
+ case 32: value.setDischargeableCapacityKwh((double) f32(input, type)); break;
+ case 33: value.setCumulativeDischargeKwh(f64(input, type)); break;
+ case 34: value.setCumulativeChargeKwh(f64(input, type)); break;
+ case 36: value.setAvgCellTemp((double) u32(input, type) - 40D); break;
+ default: skip(input, type);
+ }
+ });
+ return value;
+ }
+
+ private ElectricMeterState parseElectricMeter(byte[] bytes) throws IOException {
+ ElectricMeterState value = new ElectricMeterState();
+ read(bytes, (field, type, input) -> {
+ switch (field) {
+ case 2: value.setDeviceId(str(input, type)); break;
+ case 48: value.setAPhaseVolt((double) f32(input, type)); break;
+ case 49: value.setBPhaseVolt((double) f32(input, type)); break;
+ case 50: value.setCPhaseVolt((double) f32(input, type)); break;
+ case 51: value.setAPhaseCurrent((double) f32(input, type)); break;
+ case 52: value.setBPhaseCurrent((double) f32(input, type)); break;
+ case 53: value.setCPhaseCurrent((double) f32(input, type)); break;
+ case 54: value.setAcTotalActivePower((double) f32(input, type)); break;
+ case 69: value.setFrequency((double) f32(input, type)); break;
+ case 74: value.setAcTotalPowerFactor((double) f32(input, type)); break;
+ default: skip(input, type);
+ }
+ });
+ return value;
+ }
+
+ private TmsState parseTms(byte[] bytes) throws IOException {
+ TmsState value = new TmsState();
+ read(bytes, (field, type, input) -> {
+ switch (field) {
+ case 1: value.setDeviceId(str(input, type)); break;
+ case 2: value.setRun_status(enumName(input, type, "TmsRunStatus")); break;
+ case 3: value.setError_status(enumName(input, type, "ErrorStatus")); break;
+ case 4: value.setSupply_temp((double) f32(input, type)); break;
+ case 5: value.setReturn_temp((double) f32(input, type)); break;
+ case 8: value.setEnv_temp((double) f32(input, type)); break;
+ case 9: value.setBackwater_press((double) f32(input, type)); break;
+ case 10: value.setOut_water_press((double) f32(input, type)); break;
+ case 13: value.setCompress_status(enumName(input, type, "RunStatus")); break;
+ case 14: value.setCompress_heat_status(enumName(input, type, "RunStatus")); break;
+ case 15: value.setElectric_heat_status(enumName(input, type, "RunStatus")); break;
+ case 16: value.setPump_status(enumName(input, type, "RunStatus")); break;
+ default: skip(input, type);
+ }
+ });
+ return value;
+ }
+
private void read(byte[] bytes, Reader reader) throws IOException {
CodedInputStream input = CodedInputStream.newInstance(bytes == null ? new byte[0] : bytes);
while (!input.isAtEnd()) {
@@ -250,6 +372,18 @@
if ("CommStatus".equals(prefix)) {
return new String[]{"COMM_STATUS_UNKNOWN", "COMM_STATUS_DISCONNECTED", "COMM_STATUS_CONNECTED"}[number < 0 || number > 2 ? 0 : number];
}
+ if ("ErrorStatus".equals(prefix)) {
+ return new String[]{"ERROR_STATUS_UNKNOWN", "ERROR_STATUS_OCCURRING", "ERROR_STATUS_NONE"}[number < 0 || number > 2 ? 0 : number];
+ }
+ if ("AlarmStatus".equals(prefix)) {
+ return new String[]{"ALARM_STATUS_UNKNOWN", "ALARM_STATUS_OCCURRING", "ALARM_STATUS_NONE"}[number < 0 || number > 2 ? 0 : number];
+ }
+ if ("BatteryWorkStatus".equals(prefix)) {
+ return new String[]{"BATTERY_WORK_STATUS_UNKNOWN", "BATTERY_WORK_STATUS_CHARGING", "BATTERY_WORK_STATUS_DISCHARGING", "BATTERY_WORK_STATUS_IDLE"}[number < 0 || number > 3 ? 0 : number];
+ }
+ if ("TmsRunStatus".equals(prefix)) {
+ return new String[]{"TMS_RUN_STATUS_UNKNOWN", "TMS_RUN_STATUS_IDLE", "TMS_RUN_STATUS_READY_TO_START", "TMS_RUN_STATUS_RUNNING", "TMS_RUN_STATUS_DELAYED_SHUTDOWN", "TMS_RUN_STATUS_SELF_TEST", "TMS_RUN_STATUS_ALARMING"}[number < 0 || number > 6 ? 0 : number];
+ }
return prefix + "_" + number;
}
private static <T> T enumAt(T[] values, CodedInputStream input, int type) throws IOException {
diff --git a/ruoyi-service/ruoyi-other/src/main/resources/mapper/other/EmindEnergyChainMapper.xml b/ruoyi-service/ruoyi-other/src/main/resources/mapper/other/EmindEnergyChainMapper.xml
index 7237b1a..d4ace99 100644
--- a/ruoyi-service/ruoyi-other/src/main/resources/mapper/other/EmindEnergyChainMapper.xml
+++ b/ruoyi-service/ruoyi-other/src/main/resources/mapper/other/EmindEnergyChainMapper.xml
@@ -26,6 +26,7 @@
<result column="synced_at" property="syncedAt"/>
<result column="platform_name" property="platformName"/>
<result column="data_status" property="dataStatus"/>
+ <result column="station_type" property="stationType"/>
</resultMap>
<update id="markAllDeleted">
@@ -77,7 +78,7 @@
chain.phase_a_current, chain.phase_b_current, chain.phase_c_current,
chain.dischargeable_energy, chain.soc, chain.charged_energy_today,
chain.discharged_energy_today, chain.record_time, chain.synced_at,
- chain.source_type, chain.management_deleted,
+ chain.source_type, chain.management_deleted, chain.station_type,
station.platform_name,
CASE WHEN chain.record_time IS NULL OR chain.record_time = '' THEN 0 ELSE 1 END AS data_status
FROM t_emind_energy_chain chain
diff --git a/ruoyi-service/ruoyi-other/src/main/resources/mapper/other/EmindStationMapper.xml b/ruoyi-service/ruoyi-other/src/main/resources/mapper/other/EmindStationMapper.xml
index dae23eb..80d7efc 100644
--- a/ruoyi-service/ruoyi-other/src/main/resources/mapper/other/EmindStationMapper.xml
+++ b/ruoyi-service/ruoyi-other/src/main/resources/mapper/other/EmindStationMapper.xml
@@ -79,9 +79,9 @@
<select id="selectRemoteActiveStations" resultMap="stationResultMap">
SELECT id, station_id, name, address, province, city, longitude, latitude,
max_power, capacity, commissioning_time, platform_name, source_type,
- management_deleted, del_flag, synced_at, create_time, update_time
+ management_deleted, del_flag, synced_at, create_time, update_time, station_code
FROM t_emind_station
- WHERE source_type = 1 AND del_flag = 0 AND management_deleted = 0
+ WHERE del_flag = 0 AND management_deleted = 0
ORDER BY id
</select>
</mapper>
diff --git a/ruoyi-service/ruoyi-other/src/main/resources/mapper/other/EmindStorageDashboardMapper.xml b/ruoyi-service/ruoyi-other/src/main/resources/mapper/other/EmindStorageDashboardMapper.xml
index 7dd6e8d..c7a752a 100644
--- a/ruoyi-service/ruoyi-other/src/main/resources/mapper/other/EmindStorageDashboardMapper.xml
+++ b/ruoyi-service/ruoyi-other/src/main/resources/mapper/other/EmindStorageDashboardMapper.xml
@@ -79,4 +79,9 @@
<if test="stationId != null">AND block.station_id=#{stationId}</if>
<if test="platformNames != null and platformNames.size() > 0">AND snapshot.platform_name IN <foreach collection="platformNames" item="name" open="(" separator="," close=")">#{name}</foreach></if>
</select>
+ <select id="deleteByStationIdDay">
+ delete from t_emind_dashboard_daily
+ where station_id=#{stationId}
+ and stat_date in <foreach collection="dateSet" item="dateValue" open="(" separator="," close=")">#{dateValue}</foreach>
+ </select>
</mapper>
diff --git a/ruoyi-service/ruoyi-other/src/main/resources/sql/t_screen_content_alter.sql b/ruoyi-service/ruoyi-other/src/main/resources/sql/t_screen_content_alter.sql
index 2328ae1..6592cc3 100644
--- a/ruoyi-service/ruoyi-other/src/main/resources/sql/t_screen_content_alter.sql
+++ b/ruoyi-service/ruoyi-other/src/main/resources/sql/t_screen_content_alter.sql
@@ -1,8 +1,30 @@
-- ----------------------------
-- 1、增加大屏名称配置字段
-alter table t_screen_content add column screen_name varchar(255) default 'NULL' null comment '大屏名称';
+alter table t_screen_content add column screen_name varchar(255) default '' null comment '大屏名称';
-- 2、增加储能电站表设备编号
-alter table t_emind_station add column station_code varchar(255) default 'NULL' null comment '设备编号';
+alter table t_emind_station add column station_code varchar(255) default '' null comment '设备编号';
+ALTER TABLE t_emind_dashboard_daily MODIFY COLUMN id BIGINT NOT NULL AUTO_INCREMENT comment '主键ID';
+
+-- 3、储能能量连表增加(设备类型)
+alter table t_emind_energy_chain add column station_type varchar(255) default '' null comment '设备类型';
+
+-- 增加能量链详情表
+create table t_emind_energy_chain_detail
+(
+ id bigint auto_increment comment '主键ID'
+ primary key,
+ platform_name varchar(100) null comment '所属平台(利普芯、欧力特)',
+ station_code varchar(255) null comment '设备编号',
+ station_id varchar(255) null comment '设备ID',
+ station_type varchar(255) null comment '设备类型(与能量链里面的设备类型进行关联)',
+ detail text null comment '设备详情json字段',
+ data_source int null comment '数据来源(1系统创建,2第三方接口)',
+ create_time datetime null comment '创建时间',
+ sync_time datetime null comment '同步时间',
+ update_time datetime null comment '更新时间',
+ del_flag char default '0' not null comment '删除标志(0存在 2删除)'
+)
+ comment '能量链详情表' collate = utf8mb4_bin;
--
Gitblit v1.7.1