临时修改

This commit is contained in:
2026-02-12 21:07:41 +08:00
parent 66de6fe77c
commit 21673ecd1e
28 changed files with 2717 additions and 0 deletions

View File

@ -0,0 +1,217 @@
package com.xzzn.ems.domain;
import com.xzzn.common.annotation.Excel;
import com.xzzn.common.core.domain.BaseEntity;
import org.apache.commons.lang3.builder.ToStringBuilder;
import org.apache.commons.lang3.builder.ToStringStyle;
import java.math.BigDecimal;
/**
* 点位配置对象 ems_point_config
*/
public class EmsPointConfig extends BaseEntity {
private static final long serialVersionUID = 1L;
private Long id;
@Excel(name = "站点ID")
private String siteId;
@Excel(name = "设备类型")
private String deviceCategory;
@Excel(name = "设备ID")
private String deviceId;
@Excel(name = "点位名称")
private String pointName;
@Excel(name = "数据键")
private String dataKey;
@Excel(name = "点位描述")
private String pointDesc;
@Excel(name = "寄存器地址")
private String registerAddress;
@Excel(name = "单位")
private String dataUnit;
@Excel(name = "A系数")
private BigDecimal dataA;
@Excel(name = "K系数")
private BigDecimal dataK;
@Excel(name = "B系数")
private BigDecimal dataB;
@Excel(name = "位偏移")
private Integer dataBit;
@Excel(name = "是否报警点位", readConverterExp = "0=否,1=是")
private Integer isAlarm;
@Excel(name = "点位类型")
private String pointType;
@Excel(name = "计算表达式")
private String calcExpression;
public Long getId() {
return id;
}
public void setId(Long id) {
this.id = id;
}
public String getSiteId() {
return siteId;
}
public void setSiteId(String siteId) {
this.siteId = siteId;
}
public String getDeviceCategory() {
return deviceCategory;
}
public void setDeviceCategory(String deviceCategory) {
this.deviceCategory = deviceCategory;
}
public String getDeviceId() {
return deviceId;
}
public void setDeviceId(String deviceId) {
this.deviceId = deviceId;
}
public String getPointName() {
return pointName;
}
public void setPointName(String pointName) {
this.pointName = pointName;
}
public String getDataKey() {
return dataKey;
}
public void setDataKey(String dataKey) {
this.dataKey = dataKey;
}
public String getPointDesc() {
return pointDesc;
}
public void setPointDesc(String pointDesc) {
this.pointDesc = pointDesc;
}
public String getRegisterAddress() {
return registerAddress;
}
public void setRegisterAddress(String registerAddress) {
this.registerAddress = registerAddress;
}
public String getDataUnit() {
return dataUnit;
}
public void setDataUnit(String dataUnit) {
this.dataUnit = dataUnit;
}
public BigDecimal getDataA() {
return dataA;
}
public void setDataA(BigDecimal dataA) {
this.dataA = dataA;
}
public BigDecimal getDataK() {
return dataK;
}
public void setDataK(BigDecimal dataK) {
this.dataK = dataK;
}
public BigDecimal getDataB() {
return dataB;
}
public void setDataB(BigDecimal dataB) {
this.dataB = dataB;
}
public Integer getDataBit() {
return dataBit;
}
public void setDataBit(Integer dataBit) {
this.dataBit = dataBit;
}
public Integer getIsAlarm() {
return isAlarm;
}
public void setIsAlarm(Integer isAlarm) {
this.isAlarm = isAlarm;
}
public String getPointType() {
return pointType;
}
public void setPointType(String pointType) {
this.pointType = pointType;
}
public String getCalcExpression() {
return calcExpression;
}
public void setCalcExpression(String calcExpression) {
this.calcExpression = calcExpression;
}
@Override
public String toString() {
return new ToStringBuilder(this, ToStringStyle.MULTI_LINE_STYLE)
.append("id", getId())
.append("siteId", getSiteId())
.append("deviceCategory", getDeviceCategory())
.append("deviceId", getDeviceId())
.append("pointName", getPointName())
.append("dataKey", getDataKey())
.append("pointDesc", getPointDesc())
.append("registerAddress", getRegisterAddress())
.append("dataUnit", getDataUnit())
.append("dataA", getDataA())
.append("dataK", getDataK())
.append("dataB", getDataB())
.append("dataBit", getDataBit())
.append("isAlarm", getIsAlarm())
.append("pointType", getPointType())
.append("calcExpression", getCalcExpression())
.append("createBy", getCreateBy())
.append("createTime", getCreateTime())
.append("updateBy", getUpdateBy())
.append("updateTime", getUpdateTime())
.append("remark", getRemark())
.toString();
}
}

View File

@ -0,0 +1,58 @@
package com.xzzn.ems.domain;
import com.xzzn.common.core.domain.BaseEntity;
import java.util.Date;
/**
* 单站监控展示数据对象(按分组落到 ems_site_monitor_data_home/sbjk/tjbb
*/
public class EmsSiteMonitorData extends BaseEntity {
private static final long serialVersionUID = 1L;
private Long id;
private String siteId;
private String fieldCode;
private String fieldValue;
private Date valueTime;
public Long getId() {
return id;
}
public void setId(Long id) {
this.id = id;
}
public String getSiteId() {
return siteId;
}
public void setSiteId(String siteId) {
this.siteId = siteId;
}
public String getFieldCode() {
return fieldCode;
}
public void setFieldCode(String fieldCode) {
this.fieldCode = fieldCode;
}
public String getFieldValue() {
return fieldValue;
}
public void setFieldValue(String fieldValue) {
this.fieldValue = fieldValue;
}
public Date getValueTime() {
return valueTime;
}
public void setValueTime(Date valueTime) {
this.valueTime = valueTime;
}
}

View File

@ -0,0 +1,101 @@
package com.xzzn.ems.domain;
import com.xzzn.common.core.domain.BaseEntity;
/**
* 单站监控配置项定义对象 ems_site_monitor_item
*/
public class EmsSiteMonitorItem extends BaseEntity {
private static final long serialVersionUID = 1L;
private Long id;
private String moduleCode;
private String moduleName;
private String menuCode;
private String menuName;
private String sectionName;
private String fieldCode;
private String fieldName;
private Integer sortNo;
private Integer status;
public Long getId() {
return id;
}
public void setId(Long id) {
this.id = id;
}
public String getModuleCode() {
return moduleCode;
}
public void setModuleCode(String moduleCode) {
this.moduleCode = moduleCode;
}
public String getModuleName() {
return moduleName;
}
public void setModuleName(String moduleName) {
this.moduleName = moduleName;
}
public String getMenuCode() {
return menuCode;
}
public void setMenuCode(String menuCode) {
this.menuCode = menuCode;
}
public String getMenuName() {
return menuName;
}
public void setMenuName(String menuName) {
this.menuName = menuName;
}
public String getSectionName() {
return sectionName;
}
public void setSectionName(String sectionName) {
this.sectionName = sectionName;
}
public String getFieldCode() {
return fieldCode;
}
public void setFieldCode(String fieldCode) {
this.fieldCode = fieldCode;
}
public String getFieldName() {
return fieldName;
}
public void setFieldName(String fieldName) {
this.fieldName = fieldName;
}
public Integer getSortNo() {
return sortNo;
}
public void setSortNo(Integer sortNo) {
this.sortNo = sortNo;
}
public Integer getStatus() {
return status;
}
public void setStatus(Integer status) {
this.status = status;
}
}

View File

@ -0,0 +1,47 @@
package com.xzzn.ems.domain;
import com.xzzn.common.core.domain.BaseEntity;
/**
* 单站监控字段点位映射对象 ems_site_monitor_point_match
*/
public class EmsSiteMonitorPointMatch extends BaseEntity {
private static final long serialVersionUID = 1L;
private Long id;
private String siteId;
private String fieldCode;
private String dataPoint;
public Long getId() {
return id;
}
public void setId(Long id) {
this.id = id;
}
public String getSiteId() {
return siteId;
}
public void setSiteId(String siteId) {
this.siteId = siteId;
}
public String getFieldCode() {
return fieldCode;
}
public void setFieldCode(String fieldCode) {
this.fieldCode = fieldCode;
}
public String getDataPoint() {
return dataPoint;
}
public void setDataPoint(String dataPoint) {
this.dataPoint = dataPoint;
}
}

View File

@ -0,0 +1,31 @@
package com.xzzn.ems.domain.vo;
public class GeneralQueryPointOptionVo {
private String pointName;
private String dataKey;
private String pointDesc;
public String getPointName() {
return pointName;
}
public void setPointName(String pointName) {
this.pointName = pointName;
}
public String getDataKey() {
return dataKey;
}
public void setDataKey(String dataKey) {
this.dataKey = dataKey;
}
public String getPointDesc() {
return pointDesc;
}
public void setPointDesc(String pointDesc) {
this.pointDesc = pointDesc;
}
}

View File

@ -0,0 +1,32 @@
package com.xzzn.ems.domain.vo;
import javax.validation.constraints.NotBlank;
/**
* 按站点导入点位模板请求参数
*/
public class ImportPointTemplateRequest {
/** 目标站点ID */
@NotBlank(message = "站点ID不能为空")
private String siteId;
/** 是否覆盖目标站点已有点位配置 */
private Boolean overwrite;
public String getSiteId() {
return siteId;
}
public void setSiteId(String siteId) {
this.siteId = siteId;
}
public Boolean getOverwrite() {
return overwrite;
}
public void setOverwrite(Boolean overwrite) {
this.overwrite = overwrite;
}
}

View File

@ -0,0 +1,58 @@
package com.xzzn.ems.domain.vo;
public class PointConfigCurveRequest {
private String siteId;
private String deviceId;
private String dataKey;
private String rangeType;
private String startTime;
private String endTime;
public String getSiteId() {
return siteId;
}
public void setSiteId(String siteId) {
this.siteId = siteId;
}
public String getDeviceId() {
return deviceId;
}
public void setDeviceId(String deviceId) {
this.deviceId = deviceId;
}
public String getDataKey() {
return dataKey;
}
public void setDataKey(String dataKey) {
this.dataKey = dataKey;
}
public String getRangeType() {
return rangeType;
}
public void setRangeType(String rangeType) {
this.rangeType = rangeType;
}
public String getStartTime() {
return startTime;
}
public void setStartTime(String startTime) {
this.startTime = startTime;
}
public String getEndTime() {
return endTime;
}
public void setEndTime(String endTime) {
this.endTime = endTime;
}
}

View File

@ -0,0 +1,24 @@
package com.xzzn.ems.domain.vo;
import java.util.Date;
public class PointConfigCurveValueVo {
private Date dataTime;
private Object pointValue;
public Date getDataTime() {
return dataTime;
}
public void setDataTime(Date dataTime) {
this.dataTime = dataTime;
}
public Object getPointValue() {
return pointValue;
}
public void setPointValue(Object pointValue) {
this.pointValue = pointValue;
}
}

View File

@ -0,0 +1,31 @@
package com.xzzn.ems.domain.vo;
public class PointConfigLatestValueItemVo {
private String siteId;
private String deviceId;
private String dataKey;
public String getSiteId() {
return siteId;
}
public void setSiteId(String siteId) {
this.siteId = siteId;
}
public String getDeviceId() {
return deviceId;
}
public void setDeviceId(String deviceId) {
this.deviceId = deviceId;
}
public String getDataKey() {
return dataKey;
}
public void setDataKey(String dataKey) {
this.dataKey = dataKey;
}
}

View File

@ -0,0 +1,15 @@
package com.xzzn.ems.domain.vo;
import java.util.List;
public class PointConfigLatestValueRequest {
private List<PointConfigLatestValueItemVo> points;
public List<PointConfigLatestValueItemVo> getPoints() {
return points;
}
public void setPoints(List<PointConfigLatestValueItemVo> points) {
this.points = points;
}
}

View File

@ -0,0 +1,51 @@
package com.xzzn.ems.domain.vo;
import java.util.Date;
public class PointConfigLatestValueVo {
private String siteId;
private String deviceId;
private String dataKey;
private Object pointValue;
private Date dataTime;
public String getSiteId() {
return siteId;
}
public void setSiteId(String siteId) {
this.siteId = siteId;
}
public String getDeviceId() {
return deviceId;
}
public void setDeviceId(String deviceId) {
this.deviceId = deviceId;
}
public String getDataKey() {
return dataKey;
}
public void setDataKey(String dataKey) {
this.dataKey = dataKey;
}
public Object getPointValue() {
return pointValue;
}
public void setPointValue(Object pointValue) {
this.pointValue = pointValue;
}
public Date getDataTime() {
return dataTime;
}
public void setDataTime(Date dataTime) {
this.dataTime = dataTime;
}
}

View File

@ -0,0 +1,33 @@
package com.xzzn.ems.domain.vo;
import java.util.Date;
public class SiteMonitorDataSaveItemVo {
private String fieldCode;
private String fieldValue;
private Date valueTime;
public String getFieldCode() {
return fieldCode;
}
public void setFieldCode(String fieldCode) {
this.fieldCode = fieldCode;
}
public String getFieldValue() {
return fieldValue;
}
public void setFieldValue(String fieldValue) {
this.fieldValue = fieldValue;
}
public Date getValueTime() {
return valueTime;
}
public void setValueTime(Date valueTime) {
this.valueTime = valueTime;
}
}

View File

@ -0,0 +1,24 @@
package com.xzzn.ems.domain.vo;
import java.util.List;
public class SiteMonitorDataSaveRequest {
private String siteId;
private List<SiteMonitorDataSaveItemVo> items;
public String getSiteId() {
return siteId;
}
public void setSiteId(String siteId) {
this.siteId = siteId;
}
public List<SiteMonitorDataSaveItemVo> getItems() {
return items;
}
public void setItems(List<SiteMonitorDataSaveItemVo> items) {
this.items = items;
}
}

View File

@ -0,0 +1,27 @@
package com.xzzn.ems.domain.vo;
import java.util.Date;
/**
* 单站监控展示数据(配置项 + 当前值)
*/
public class SiteMonitorProjectDisplayVo extends SiteMonitorProjectPointMappingVo {
private String fieldValue;
private Date valueTime;
public String getFieldValue() {
return fieldValue;
}
public void setFieldValue(String fieldValue) {
this.fieldValue = fieldValue;
}
public Date getValueTime() {
return valueTime;
}
public void setValueTime(Date valueTime) {
this.valueTime = valueTime;
}
}

View File

@ -0,0 +1,26 @@
package com.xzzn.ems.domain.vo;
import java.util.List;
public class SiteMonitorProjectPointMappingSaveRequest {
private String siteId;
private List<SiteMonitorProjectPointMappingVo> mappings;
public String getSiteId() {
return siteId;
}
public void setSiteId(String siteId) {
this.siteId = siteId;
}
public List<SiteMonitorProjectPointMappingVo> getMappings() {
return mappings;
}
public void setMappings(List<SiteMonitorProjectPointMappingVo> mappings) {
this.mappings = mappings;
}
}

View File

@ -0,0 +1,84 @@
package com.xzzn.ems.domain.vo;
public class SiteMonitorProjectPointMappingVo {
private String moduleCode;
private String moduleName;
private String menuCode;
private String menuName;
private String sectionName;
private String fieldCode;
private String fieldName;
private String dataPoint;
public String getModuleCode() {
return moduleCode;
}
public void setModuleCode(String moduleCode) {
this.moduleCode = moduleCode;
}
public String getModuleName() {
return moduleName;
}
public void setModuleName(String moduleName) {
this.moduleName = moduleName;
}
public String getFieldCode() {
return fieldCode;
}
public String getMenuCode() {
return menuCode;
}
public void setMenuCode(String menuCode) {
this.menuCode = menuCode;
}
public String getMenuName() {
return menuName;
}
public void setMenuName(String menuName) {
this.menuName = menuName;
}
public String getSectionName() {
return sectionName;
}
public void setSectionName(String sectionName) {
this.sectionName = sectionName;
}
public void setFieldCode(String fieldCode) {
this.fieldCode = fieldCode;
}
public String getFieldName() {
return fieldName;
}
public void setFieldName(String fieldName) {
this.fieldName = fieldName;
}
public String getDataPoint() {
return dataPoint;
}
public void setDataPoint(String dataPoint) {
this.dataPoint = dataPoint;
}
}

View File

@ -0,0 +1,44 @@
package com.xzzn.ems.mapper;
import com.xzzn.ems.domain.EmsPointConfig;
import com.xzzn.ems.domain.vo.GeneralQueryPointOptionVo;
import org.apache.ibatis.annotations.Param;
import java.util.List;
public interface EmsPointConfigMapper {
EmsPointConfig selectEmsPointConfigById(Long id);
List<EmsPointConfig> selectEmsPointConfigList(EmsPointConfig emsPointConfig);
int insertEmsPointConfig(EmsPointConfig emsPointConfig);
int updateEmsPointConfig(EmsPointConfig emsPointConfig);
int deleteEmsPointConfigById(Long id);
int deleteEmsPointConfigByIds(Long[] ids);
int countBySiteId(@Param("siteId") String siteId);
int deleteBySiteId(@Param("siteId") String siteId);
int copyTemplateToSite(@Param("templateSiteId") String templateSiteId,
@Param("targetSiteId") String targetSiteId,
@Param("operName") String operName);
String getRegisterAddress(@Param("siteId") String siteId,
@Param("deviceCategory") String deviceCategory,
@Param("deviceId") String deviceId,
@Param("dataKey") String dataKey);
List<GeneralQueryPointOptionVo> getPointNameList(@Param("siteIds") List<String> siteIds,
@Param("deviceCategory") String deviceCategory,
@Param("deviceId") String deviceId,
@Param("pointName") String pointName);
List<EmsPointConfig> getConfigListForGeneralQuery(@Param("siteIds") List<String> siteIds,
@Param("deviceCategory") String deviceCategory,
@Param("pointNames") List<String> pointNames,
@Param("deviceIds") List<String> deviceIds);
}

View File

@ -0,0 +1,28 @@
package com.xzzn.ems.mapper;
import org.apache.ibatis.annotations.Param;
/**
* 单站监控展示数据 Mapper
*/
public interface EmsSiteMonitorDataMapper {
String selectHistoryJsonByMinute(@Param("tableName") String tableName,
@Param("siteId") String siteId,
@Param("statisMinute") java.util.Date statisMinute);
int upsertHistoryJsonByMinute(@Param("tableName") String tableName,
@Param("siteId") String siteId,
@Param("statisMinute") java.util.Date statisMinute,
@Param("dataJson") String dataJson,
@Param("operName") String operName);
int updateHistoryHotColumns(@Param("tableName") String tableName,
@Param("siteId") String siteId,
@Param("statisMinute") java.util.Date statisMinute,
@Param("hotSoc") String hotSoc,
@Param("hotTotalActivePower") String hotTotalActivePower,
@Param("hotTotalReactivePower") String hotTotalReactivePower,
@Param("hotDayChargedCap") String hotDayChargedCap,
@Param("hotDayDisChargedCap") String hotDayDisChargedCap,
@Param("operName") String operName);
}

View File

@ -0,0 +1,12 @@
package com.xzzn.ems.mapper;
import com.xzzn.ems.domain.EmsSiteMonitorItem;
import java.util.List;
/**
* 单站监控配置项定义 Mapper
*/
public interface EmsSiteMonitorItemMapper {
List<EmsSiteMonitorItem> selectEnabledList();
}

View File

@ -0,0 +1,17 @@
package com.xzzn.ems.mapper;
import com.xzzn.ems.domain.EmsSiteMonitorPointMatch;
import org.apache.ibatis.annotations.Param;
import java.util.List;
/**
* 单站监控字段点位映射 Mapper
*/
public interface EmsSiteMonitorPointMatchMapper {
List<EmsSiteMonitorPointMatch> selectBySiteId(@Param("siteId") String siteId);
int deleteBySiteId(@Param("siteId") String siteId);
int insertBatch(@Param("list") List<EmsSiteMonitorPointMatch> list);
}

View File

@ -0,0 +1,33 @@
package com.xzzn.ems.service;
import com.xzzn.ems.domain.EmsPointConfig;
import com.xzzn.ems.domain.vo.ImportPointTemplateRequest;
import com.xzzn.ems.domain.vo.PointConfigCurveRequest;
import com.xzzn.ems.domain.vo.PointConfigCurveValueVo;
import com.xzzn.ems.domain.vo.PointConfigLatestValueRequest;
import com.xzzn.ems.domain.vo.PointConfigLatestValueVo;
import org.springframework.web.multipart.MultipartFile;
import java.util.List;
public interface IEmsPointConfigService {
List<EmsPointConfig> selectPointConfigList(EmsPointConfig pointConfig);
EmsPointConfig selectPointConfigById(Long id);
int insertPointConfig(EmsPointConfig pointConfig, String operName);
int updatePointConfig(EmsPointConfig pointConfig, String operName);
int deletePointConfigByIds(Long[] ids);
String importTemplateBySite(ImportPointTemplateRequest request, String operName);
String importCsvBySite(String siteId, Boolean overwrite, MultipartFile file, String operName);
String getRegisterAddress(String siteId, String deviceCategory, String deviceId, String dataKey);
List<PointConfigLatestValueVo> getLatestValues(PointConfigLatestValueRequest request);
List<PointConfigCurveValueVo> getCurveData(PointConfigCurveRequest request);
}

View File

@ -0,0 +1,616 @@
package com.xzzn.ems.service;
import com.fasterxml.jackson.databind.JsonNode;
import com.fasterxml.jackson.databind.ObjectMapper;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Component;
import javax.annotation.PostConstruct;
import java.io.BufferedReader;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.OutputStream;
import java.math.BigDecimal;
import java.net.HttpURLConnection;
import java.net.URLEncoder;
import java.nio.charset.StandardCharsets;
import java.time.Instant;
import java.util.ArrayList;
import java.util.Collections;
import java.util.Date;
import java.util.List;
import java.util.HashMap;
import java.util.Map;
@Component
public class InfluxPointDataWriter {
private static final Logger log = LoggerFactory.getLogger(InfluxPointDataWriter.class);
private static final ObjectMapper OBJECT_MAPPER = new ObjectMapper();
@Value("${influxdb.enabled:true}")
private boolean enabled;
@Value("${influxdb.url:}")
private String url;
@Value("${influxdb.username:}")
private String username;
@Value("${influxdb.password:}")
private String password;
@Value("${influxdb.api-token:}")
private String apiToken;
@Value("${influxdb.database:ems_point_data}")
private String database;
@Value("${influxdb.retention-policy:autogen}")
private String retentionPolicy;
@Value("${influxdb.measurement:mqtt_point_data}")
private String measurement;
@Value("${influxdb.write-method:POST}")
private String writeMethod;
@Value("${influxdb.read-method:GET}")
private String readMethod;
@Value("${influxdb.write-path:/write}")
private String writePath;
@Value("${influxdb.query-path:/query}")
private String queryPath;
@Value("${influxdb.org:}")
private String org;
@Value("${influxdb.bucket:}")
private String bucket;
@PostConstruct
public void init() {
if (!enabled) {
log.info("InfluxDB 写入已禁用");
return;
}
if (url == null || url.trim().isEmpty()) {
log.warn("InfluxDB URL 未配置,跳过初始化");
return;
}
log.info("InfluxDB 已启用 HTTP 接入, url: {}, database: {}", url, database);
}
public void writeBatch(List<PointWritePayload> payloads) {
if (!enabled || payloads == null || payloads.isEmpty()) {
return;
}
try {
StringBuilder body = new StringBuilder();
for (PointWritePayload payload : payloads) {
if (payload == null || payload.getPointValue() == null) {
continue;
}
long time = payload.getDataTime() == null ? System.currentTimeMillis() : payload.getDataTime().getTime();
body.append(measurement)
.append(",site_id=").append(escapeLineTag(payload.getSiteId()))
.append(",device_id=").append(escapeLineTag(payload.getDeviceId()))
.append(",point_key=").append(escapeLineTag(payload.getPointKey()))
.append(" value=").append(payload.getPointValue().toPlainString())
.append(" ").append(time)
.append("\n");
}
if (body.length() == 0) {
return;
}
String writeUrl = buildWriteUrl();
if (isBlank(writeUrl)) {
log.warn("写入 InfluxDB 失败v2 写入地址未构建成功,请检查 influxdb.org / influxdb.bucket 配置");
return;
}
HttpResult result = executeRequest(methodOrDefault(writeMethod, "POST"), writeUrl, body.toString());
if (result.code < 200 || result.code >= 300) {
if (result.code == 404 && isV2WritePath() && isOrgOrBucketMissing(result.body)) {
if (ensureV2OrgAndBucket()) {
HttpResult retryResult = executeRequest(methodOrDefault(writeMethod, "POST"), writeUrl, body.toString());
if (retryResult.code >= 200 && retryResult.code < 300) {
log.info("InfluxDB org/bucket 自动创建成功,写入已恢复");
return;
}
log.warn("InfluxDB 重试写入失败HTTP状态码: {}, url: {}, body: {}", retryResult.code, writeUrl, safeLog(retryResult.body));
return;
}
}
log.warn("写入 InfluxDB 失败HTTP状态码: {}, url: {}, body: {}", result.code, writeUrl, safeLog(result.body));
}
} catch (Exception e) {
log.warn("写入 InfluxDB 失败: {}", e.getMessage());
}
}
public List<PointValue> queryCurveData(String siteId, String deviceId, String pointKey, Date startTime, Date endTime) {
if (!enabled) {
return Collections.emptyList();
}
if (isBlank(siteId) || isBlank(deviceId) || isBlank(pointKey) || startTime == null || endTime == null) {
return Collections.emptyList();
}
String normalizedSiteId = siteId.trim();
String normalizedDeviceId = deviceId.trim();
String normalizedPointKey = pointKey.trim();
String influxQl = String.format(
"SELECT \"value\" FROM \"%s\" WHERE \"site_id\" = '%s' AND \"device_id\" = '%s' AND \"point_key\" = '%s' " +
"AND time >= %dms AND time <= %dms ORDER BY time ASC",
measurement,
escapeTagValue(normalizedSiteId),
escapeTagValue(normalizedDeviceId),
escapeTagValue(normalizedPointKey),
startTime.getTime(),
endTime.getTime()
);
try {
String queryUrl = buildQueryUrl(influxQl);
List<PointValue> values = parseInfluxQlResponse(executeRequestWithResponse(methodOrDefault(readMethod, "GET"), queryUrl));
if (!values.isEmpty()) {
return values;
}
// 兼容 dataKey 大小写差异,避免点位 key 字母大小写不一致导致查不到曲线
String regexQuery = String.format(
"SELECT \"value\" FROM \"%s\" WHERE \"site_id\" = '%s' AND \"device_id\" = '%s' AND \"point_key\" =~ /(?i)^%s$/ " +
"AND time >= %dms AND time <= %dms ORDER BY time ASC",
measurement,
escapeTagValue(normalizedSiteId),
escapeTagValue(normalizedDeviceId),
escapeRegex(normalizedPointKey),
startTime.getTime(),
endTime.getTime()
);
values = parseInfluxQlResponse(executeRequestWithResponse(methodOrDefault(readMethod, "GET"), buildQueryUrl(regexQuery)));
return values;
} catch (Exception e) {
log.warn("查询 InfluxDB 曲线失败: {}", e.getMessage());
return Collections.emptyList();
}
}
private String buildWriteUrl() {
if (isV2WritePath()) {
return buildV2WriteUrl();
}
StringBuilder sb = new StringBuilder(trimTrailingSlash(url));
sb.append(normalizePath(writePath)).append("?db=").append(urlEncode(database));
if (!isBlank(retentionPolicy)) {
sb.append("&rp=").append(urlEncode(retentionPolicy));
}
sb.append("&precision=ms");
return sb.toString();
}
private String buildQueryUrl(String influxQl) {
String queryDb = database;
if (isV2WritePath() && !isBlank(bucket)) {
queryDb = bucket;
}
StringBuilder queryUrl = new StringBuilder(trimTrailingSlash(url))
.append(normalizePath(queryPath))
.append("?db=").append(urlEncode(queryDb))
.append("&epoch=ms&q=").append(urlEncode(influxQl));
if (!isBlank(retentionPolicy)) {
queryUrl.append("&rp=").append(urlEncode(retentionPolicy));
}
return queryUrl.toString();
}
private String buildV2WriteUrl() {
String currentBucket = isBlank(bucket) ? database : bucket;
if (isBlank(org) || isBlank(currentBucket)) {
return null;
}
return trimTrailingSlash(url)
+ "/api/v2/write?org=" + urlEncode(org)
+ "&bucket=" + urlEncode(currentBucket)
+ "&precision=ms";
}
private HttpResult executeRequest(String method, String requestUrl, String body) throws Exception {
HttpURLConnection connection = openConnection(method, requestUrl, "text/plain; charset=UTF-8");
try {
if (body != null) {
connection.setDoOutput(true);
try (OutputStream os = connection.getOutputStream()) {
os.write(body.getBytes(StandardCharsets.UTF_8));
}
}
int code = connection.getResponseCode();
InputStream is = (code >= 200 && code < 300) ? connection.getInputStream() : connection.getErrorStream();
return new HttpResult(code, readStream(is));
} finally {
connection.disconnect();
}
}
private String executeRequestWithResponse(String method, String requestUrl) throws Exception {
HttpURLConnection connection = openConnection(method, requestUrl, "text/plain; charset=UTF-8");
try {
int code = connection.getResponseCode();
InputStream is = (code >= 200 && code < 300) ? connection.getInputStream() : connection.getErrorStream();
return readStream(is);
} finally {
connection.disconnect();
}
}
private String readStream(InputStream is) throws Exception {
if (is == null) {
return "";
}
try (BufferedReader reader = new BufferedReader(new InputStreamReader(is, StandardCharsets.UTF_8))) {
StringBuilder sb = new StringBuilder();
String line;
while ((line = reader.readLine()) != null) {
sb.append(line);
}
return sb.toString();
}
}
private HttpResult executeJsonRequest(String method, String requestUrl, String jsonBody) throws Exception {
HttpURLConnection connection = openConnection(method, requestUrl, "application/json; charset=UTF-8");
try {
if (jsonBody != null) {
connection.setDoOutput(true);
try (OutputStream os = connection.getOutputStream()) {
os.write(jsonBody.getBytes(StandardCharsets.UTF_8));
}
}
int code = connection.getResponseCode();
InputStream is = (code >= 200 && code < 300) ? connection.getInputStream() : connection.getErrorStream();
return new HttpResult(code, readStream(is));
} finally {
connection.disconnect();
}
}
private HttpURLConnection openConnection(String method, String requestUrl, String contentType) throws Exception {
HttpURLConnection connection = (HttpURLConnection) new java.net.URL(requestUrl).openConnection();
connection.setRequestMethod(method);
connection.setConnectTimeout(5000);
connection.setReadTimeout(8000);
connection.setRequestProperty("Accept", "application/json");
connection.setRequestProperty("Content-Type", contentType);
if (!isBlank(apiToken)) {
connection.setRequestProperty("Authorization", "Token " + apiToken.trim());
} else if (!isBlank(username) || !isBlank(password)) {
String basic = java.util.Base64.getEncoder()
.encodeToString((safe(username) + ":" + safe(password)).getBytes(StandardCharsets.UTF_8));
connection.setRequestProperty("Authorization", "Basic " + basic);
}
return connection;
}
private String escapeLineTag(String value) {
if (value == null) {
return "";
}
return value.replace("\\", "\\\\")
.replace(",", "\\,")
.replace(" ", "\\ ")
.replace("=", "\\=");
}
private String trimTrailingSlash(String v) {
if (v == null) {
return "";
}
String result = v.trim();
while (result.endsWith("/")) {
result = result.substring(0, result.length() - 1);
}
return result;
}
private String urlEncode(String value) {
try {
return URLEncoder.encode(safe(value), StandardCharsets.UTF_8.name());
} catch (Exception e) {
return safe(value);
}
}
private String safe(String value) {
return value == null ? "" : value;
}
private boolean isV2WritePath() {
return "/api/v2/write".equals(normalizePath(writePath));
}
private boolean isOrgOrBucketMissing(String responseBody) {
if (isBlank(responseBody)) {
return false;
}
String lower = responseBody.toLowerCase();
return (lower.contains("organization") && lower.contains("not found"))
|| (lower.contains("bucket") && lower.contains("not found"));
}
private boolean ensureV2OrgAndBucket() {
try {
if (isBlank(org)) {
log.warn("InfluxDB 自动创建 organization 失败org 配置为空");
return false;
}
String currentBucket = isBlank(bucket) ? database : bucket;
String orgId = queryOrgId(org);
if (isBlank(orgId)) {
orgId = createOrg(org);
}
if (isBlank(orgId)) {
log.warn("InfluxDB 自动创建 organization 失败org={}", org);
return false;
}
if (!bucketExists(org, currentBucket)) {
if (!createBucket(orgId, currentBucket)) {
log.warn("InfluxDB 自动创建 bucket 失败org={}, bucket={}", org, currentBucket);
return false;
}
}
return true;
} catch (Exception ex) {
log.warn("InfluxDB 自动创建 org/bucket 异常: {}", ex.getMessage());
return false;
}
}
private String queryOrgId(String orgName) throws Exception {
String requestUrl = trimTrailingSlash(url) + "/api/v2/orgs?org=" + urlEncode(orgName);
HttpResult result = executeJsonRequest("GET", requestUrl, null);
if (result.code < 200 || result.code >= 300 || isBlank(result.body)) {
log.warn("查询 organization 失败status={}, org={}, body={}", result.code, orgName, safeLog(result.body));
return null;
}
JsonNode root = OBJECT_MAPPER.readTree(result.body);
JsonNode orgs = root.path("orgs");
if (orgs.isArray() && orgs.size() > 0) {
JsonNode first = orgs.get(0);
if (first != null) {
String id = first.path("id").asText(null);
if (!isBlank(id)) {
return id;
}
}
}
return null;
}
private String createOrg(String orgName) throws Exception {
String requestUrl = trimTrailingSlash(url) + "/api/v2/orgs";
Map<String, Object> payload = new HashMap<>();
payload.put("name", orgName);
String body = OBJECT_MAPPER.writeValueAsString(payload);
HttpResult result = executeJsonRequest("POST", requestUrl, body);
if ((result.code < 200 || result.code >= 300) || isBlank(result.body)) {
log.warn("创建 organization 失败status={}, org={}, body={}", result.code, orgName, safeLog(result.body));
return null;
}
JsonNode root = OBJECT_MAPPER.readTree(result.body);
String id = root.path("id").asText(null);
return isBlank(id) ? null : id;
}
private boolean bucketExists(String orgName, String bucketName) throws Exception {
String requestUrl = trimTrailingSlash(url)
+ "/api/v2/buckets?name=" + urlEncode(bucketName)
+ "&org=" + urlEncode(orgName);
HttpResult result = executeJsonRequest("GET", requestUrl, null);
if (result.code < 200 || result.code >= 300 || isBlank(result.body)) {
log.warn("查询 bucket 失败status={}, org={}, bucket={}, body={}", result.code, orgName, bucketName, safeLog(result.body));
return false;
}
JsonNode root = OBJECT_MAPPER.readTree(result.body);
JsonNode buckets = root.path("buckets");
return buckets.isArray() && buckets.size() > 0;
}
private boolean createBucket(String orgId, String bucketName) throws Exception {
String requestUrl = trimTrailingSlash(url) + "/api/v2/buckets";
Map<String, Object> payload = new HashMap<>();
payload.put("orgID", orgId);
payload.put("name", bucketName);
String body = OBJECT_MAPPER.writeValueAsString(payload);
HttpResult result = executeJsonRequest("POST", requestUrl, body);
if (result.code < 200 || result.code >= 300) {
log.warn("创建 bucket 失败status={}, orgId={}, bucket={}, body={}", result.code, orgId, bucketName, safeLog(result.body));
}
return result.code >= 200 && result.code < 300;
}
private String methodOrDefault(String method, String defaultMethod) {
return isBlank(method) ? defaultMethod : method.trim().toUpperCase();
}
private String normalizePath(String path) {
if (isBlank(path)) {
return "/";
}
String p = path.trim();
return p.startsWith("/") ? p : "/" + p;
}
private String safeLog(String body) {
if (body == null) {
return "";
}
return body.length() > 200 ? body.substring(0, 200) : body;
}
private Date parseInfluxTime(Object timeObject) {
if (timeObject == null) {
return null;
}
if (timeObject instanceof Number) {
return new Date(((Number) timeObject).longValue());
}
try {
return Date.from(Instant.parse(String.valueOf(timeObject)));
} catch (Exception e) {
return null;
}
}
private BigDecimal toBigDecimal(Object valueObject) {
if (valueObject == null) {
return null;
}
if (valueObject instanceof BigDecimal) {
return (BigDecimal) valueObject;
}
if (valueObject instanceof Number) {
return new BigDecimal(valueObject.toString());
}
try {
return new BigDecimal(String.valueOf(valueObject));
} catch (Exception e) {
return null;
}
}
private String escapeTagValue(String value) {
return value == null ? "" : value.replace("\\", "\\\\").replace("'", "\\'");
}
private String escapeRegex(String value) {
if (value == null) {
return "";
}
return value.replace("\\", "\\\\")
.replace("/", "\\/")
.replace(".", "\\.")
.replace("(", "\\(")
.replace(")", "\\)")
.replace("[", "\\[")
.replace("]", "\\]")
.replace("{", "\\{")
.replace("}", "\\}")
.replace("^", "\\^")
.replace("$", "\\$")
.replace("*", "\\*")
.replace("+", "\\+")
.replace("?", "\\?")
.replace("|", "\\|");
}
private List<PointValue> parseInfluxQlResponse(String response) throws Exception {
if (isBlank(response)) {
return Collections.emptyList();
}
List<PointValue> values = new ArrayList<>();
JsonNode root = OBJECT_MAPPER.readTree(response);
JsonNode resultsNode = root.path("results");
if (!resultsNode.isArray()) {
return values;
}
for (JsonNode result : resultsNode) {
JsonNode seriesArray = result.path("series");
if (!seriesArray.isArray()) {
continue;
}
for (JsonNode series : seriesArray) {
JsonNode rows = series.path("values");
if (!rows.isArray()) {
continue;
}
for (JsonNode row : rows) {
if (!row.isArray() || row.size() < 2) {
continue;
}
Date dataTime = parseInfluxTime(row.get(0).isNumber() ? row.get(0).asLong() : row.get(0).asText());
BigDecimal pointValue = toBigDecimal(row.get(1).isNumber() ? row.get(1).asText() : row.get(1).asText(null));
if (dataTime == null || pointValue == null) {
continue;
}
values.add(new PointValue(dataTime, pointValue));
}
}
}
return values;
}
private boolean isBlank(String value) {
return value == null || value.trim().isEmpty();
}
public static class PointWritePayload {
private final String siteId;
private final String deviceId;
private final String pointKey;
private final BigDecimal pointValue;
private final Date dataTime;
public PointWritePayload(String siteId, String deviceId, String pointKey, BigDecimal pointValue, Date dataTime) {
this.siteId = siteId;
this.deviceId = deviceId;
this.pointKey = pointKey;
this.pointValue = pointValue;
this.dataTime = dataTime;
}
public String getSiteId() {
return siteId;
}
public String getDeviceId() {
return deviceId;
}
public String getPointKey() {
return pointKey;
}
public BigDecimal getPointValue() {
return pointValue;
}
public Date getDataTime() {
return dataTime;
}
}
public static class PointValue {
private final Date dataTime;
private final BigDecimal pointValue;
public PointValue(Date dataTime, BigDecimal pointValue) {
this.dataTime = dataTime;
this.pointValue = pointValue;
}
public Date getDataTime() {
return dataTime;
}
public BigDecimal getPointValue() {
return pointValue;
}
}
private static class HttpResult {
private final int code;
private final String body;
private HttpResult(int code, String body) {
this.code = code;
this.body = body;
}
}
}

View File

@ -0,0 +1,668 @@
package com.xzzn.ems.service.impl;
import com.alibaba.fastjson2.JSON;
import com.alibaba.fastjson2.JSONObject;
import com.xzzn.common.exception.ServiceException;
import com.xzzn.common.constant.RedisKeyConstants;
import com.xzzn.common.core.redis.RedisCache;
import com.xzzn.common.utils.DateUtils;
import com.xzzn.common.utils.StringUtils;
import com.xzzn.ems.domain.EmsPointConfig;
import com.xzzn.ems.domain.vo.ImportPointTemplateRequest;
import com.xzzn.ems.domain.vo.PointConfigCurveRequest;
import com.xzzn.ems.domain.vo.PointConfigCurveValueVo;
import com.xzzn.ems.domain.vo.PointConfigLatestValueItemVo;
import com.xzzn.ems.domain.vo.PointConfigLatestValueRequest;
import com.xzzn.ems.domain.vo.PointConfigLatestValueVo;
import com.xzzn.ems.mapper.EmsPointConfigMapper;
import com.xzzn.ems.service.IEmsPointConfigService;
import com.xzzn.ems.service.InfluxPointDataWriter;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.web.multipart.MultipartFile;
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.math.BigDecimal;
import java.nio.charset.StandardCharsets;
import java.sql.Timestamp;
import java.time.LocalDateTime;
import java.time.format.DateTimeFormatter;
import java.time.format.DateTimeParseException;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Date;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Locale;
import java.util.regex.Pattern;
import java.util.stream.Collectors;
@Service
public class EmsPointConfigServiceImpl implements IEmsPointConfigService {
private static final String TEMPLATE_SITE_ID = "DEFAULT";
private static final Pattern DB_NAME_PATTERN = Pattern.compile("^[A-Za-z0-9_]+$");
private static final Pattern INTEGER_PATTERN = Pattern.compile("^-?\\d+$");
private static final Pattern DECIMAL_PATTERN = Pattern.compile("^-?\\d+(\\.\\d+)?$");
private static final Pattern CALC_EXPRESSION_PATTERN = Pattern.compile("^[0-9A-Za-z_+\\-*/().\\s]+$");
private static final DateTimeFormatter DATETIME_FORMATTER = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss");
@Autowired
private EmsPointConfigMapper emsPointConfigMapper;
@Autowired
private RedisCache redisCache;
@Autowired
private InfluxPointDataWriter influxPointDataWriter;
@Override
public List<EmsPointConfig> selectPointConfigList(EmsPointConfig pointConfig) {
return emsPointConfigMapper.selectEmsPointConfigList(pointConfig);
}
@Override
public EmsPointConfig selectPointConfigById(Long id) {
return emsPointConfigMapper.selectEmsPointConfigById(id);
}
@Override
public int insertPointConfig(EmsPointConfig pointConfig, String operName) {
if (pointConfig == null || StringUtils.isBlank(pointConfig.getSiteId())) {
throw new ServiceException("站点ID不能为空");
}
normalizeAndValidatePointConfig(pointConfig);
pointConfig.setCreateBy(operName);
pointConfig.setUpdateBy(operName);
int rows = emsPointConfigMapper.insertEmsPointConfig(pointConfig);
if (rows > 0) {
invalidatePointConfigCache(pointConfig.getSiteId(), pointConfig.getDeviceId());
}
return rows;
}
@Override
public int updatePointConfig(EmsPointConfig pointConfig, String operName) {
EmsPointConfig oldConfig = pointConfig.getId() == null ? null : emsPointConfigMapper.selectEmsPointConfigById(pointConfig.getId());
normalizeAndValidatePointConfig(pointConfig);
pointConfig.setUpdateBy(operName);
int rows = emsPointConfigMapper.updateEmsPointConfig(pointConfig);
if (rows > 0) {
if (oldConfig != null) {
invalidatePointConfigCache(oldConfig.getSiteId(), oldConfig.getDeviceId());
}
invalidatePointConfigCache(pointConfig.getSiteId(), pointConfig.getDeviceId());
}
return rows;
}
@Override
public int deletePointConfigByIds(Long[] ids) {
if (ids != null) {
for (Long id : ids) {
EmsPointConfig oldConfig = emsPointConfigMapper.selectEmsPointConfigById(id);
if (oldConfig != null) {
invalidatePointConfigCache(oldConfig.getSiteId(), oldConfig.getDeviceId());
}
}
}
return emsPointConfigMapper.deleteEmsPointConfigByIds(ids);
}
@Override
@Transactional(rollbackFor = Exception.class)
public String importTemplateBySite(ImportPointTemplateRequest request, String operName) {
String targetSiteId = request.getSiteId();
if (StringUtils.isBlank(targetSiteId)) {
throw new ServiceException("站点ID不能为空");
}
if (TEMPLATE_SITE_ID.equals(targetSiteId)) {
throw new ServiceException("模板站点不支持作为导入目标站点");
}
int templateCount = emsPointConfigMapper.countBySiteId(TEMPLATE_SITE_ID);
if (templateCount <= 0) {
throw new ServiceException("模板点位配置不存在,无法导入");
}
boolean overwrite = Boolean.TRUE.equals(request.getOverwrite());
int targetCount = emsPointConfigMapper.countBySiteId(targetSiteId);
if (targetCount > 0 && !overwrite) {
throw new ServiceException("目标站点已存在点位配置,请勾选“覆盖已存在数据”后重试");
}
if (targetCount > 0) {
emsPointConfigMapper.deleteBySiteId(targetSiteId);
}
int importCount = emsPointConfigMapper.copyTemplateToSite(TEMPLATE_SITE_ID, targetSiteId, operName);
invalidatePointConfigCacheBySite(targetSiteId);
return String.format("导入成功:站点 %s点位 %d 条", targetSiteId, importCount);
}
@Override
@Transactional(rollbackFor = Exception.class)
public String importCsvBySite(String siteId, Boolean overwrite, MultipartFile file, String operName) {
if (StringUtils.isBlank(siteId)) {
throw new ServiceException("站点ID不能为空");
}
if (!DB_NAME_PATTERN.matcher(siteId).matches()) {
throw new ServiceException(String.format("站点ID不合法siteId=%s", siteId));
}
if (TEMPLATE_SITE_ID.equals(siteId)) {
throw new ServiceException("模板站点不支持作为导入目标站点");
}
if (file == null || file.isEmpty()) {
throw new ServiceException("请上传CSV文件");
}
if (!StringUtils.endsWithIgnoreCase(file.getOriginalFilename(), ".csv")) {
throw new ServiceException("仅支持上传CSV文件");
}
boolean overwriteFlag = Boolean.TRUE.equals(overwrite);
int targetCount = emsPointConfigMapper.countBySiteId(siteId);
if (targetCount > 0 && !overwriteFlag) {
throw new ServiceException("目标站点已存在点位配置,请勾选“覆盖已存在点位数据”后重试");
}
List<EmsPointConfig> pointConfigList = parseCsv(file, siteId);
if (pointConfigList.isEmpty()) {
throw new ServiceException("CSV没有可导入的数据");
}
if (targetCount > 0) {
emsPointConfigMapper.deleteBySiteId(siteId);
}
int importCount = 0;
for (EmsPointConfig pointConfig : pointConfigList) {
pointConfig.setCreateBy(operName);
pointConfig.setUpdateBy(operName);
importCount += emsPointConfigMapper.insertEmsPointConfig(pointConfig);
}
invalidatePointConfigCacheBySite(siteId);
return String.format("导入成功:站点 %s点位 %d 条", siteId, importCount);
}
@Override
public String getRegisterAddress(String siteId, String deviceCategory, String deviceId, String dataKey) {
if (StringUtils.isAnyBlank(siteId, deviceCategory, deviceId, dataKey)) {
return null;
}
return emsPointConfigMapper.getRegisterAddress(siteId, deviceCategory, deviceId, dataKey);
}
@Override
public List<PointConfigLatestValueVo> getLatestValues(PointConfigLatestValueRequest request) {
List<PointConfigLatestValueVo> result = new ArrayList<>();
if (request == null || request.getPoints() == null || request.getPoints().isEmpty()) {
return result;
}
Map<String, Map<String, EmsPointConfig>> configMapCache = new HashMap<>();
for (PointConfigLatestValueItemVo item : request.getPoints()) {
if (item == null || StringUtils.isAnyBlank(item.getSiteId(), item.getDeviceId(), item.getDataKey())) {
continue;
}
PointConfigLatestValueVo latestValue = queryLatestValueFromRedis(item, configMapCache);
result.add(latestValue);
}
return result;
}
@Override
public List<PointConfigCurveValueVo> getCurveData(PointConfigCurveRequest request) {
if (request == null || StringUtils.isAnyBlank(request.getSiteId(), request.getDeviceId(), request.getDataKey())) {
return new ArrayList<>();
}
String siteId = StringUtils.trim(request.getSiteId());
String deviceId = StringUtils.trim(request.getDeviceId());
String dataKey = StringUtils.trim(request.getDataKey());
if (StringUtils.isAnyBlank(siteId, deviceId, dataKey)) {
return new ArrayList<>();
}
Date[] range = resolveTimeRange(request);
return queryCurveDataFromInflux(siteId, deviceId, dataKey, range[0], range[1]);
}
private PointConfigLatestValueVo queryLatestValueFromRedis(PointConfigLatestValueItemVo item,
Map<String, Map<String, EmsPointConfig>> configMapCache) {
PointConfigLatestValueVo vo = new PointConfigLatestValueVo();
vo.setSiteId(item.getSiteId());
vo.setDeviceId(item.getDeviceId());
vo.setDataKey(item.getDataKey());
String redisKey = RedisKeyConstants.ORIGINAL_MQTT_DATA + item.getSiteId() + "_" + item.getDeviceId();
Object raw = redisCache.getCacheObject(redisKey);
if (raw == null) {
return vo;
}
JSONObject root = toJsonObject(raw);
if (root == null) {
return vo;
}
JSONObject dataObject = extractDataObject(root);
if (dataObject == null) {
return vo;
}
Object rawValue = getValueIgnoreCase(dataObject, item.getDataKey());
BigDecimal pointValue = StringUtils.getBigDecimal(rawValue);
if (pointValue != null) {
EmsPointConfig pointConfig = getPointConfig(item.getSiteId(), item.getDeviceId(), item.getDataKey(), configMapCache);
vo.setPointValue(convertPointValue(pointValue, pointConfig));
}
vo.setDataTime(extractDataTime(root));
return vo;
}
private List<PointConfigCurveValueVo> queryCurveDataFromInflux(String siteId, String deviceId, String dataKey, Date startTime, Date endTime) {
List<InfluxPointDataWriter.PointValue> values = influxPointDataWriter.queryCurveData(siteId, deviceId, dataKey, startTime, endTime);
if (values == null || values.isEmpty()) {
return new ArrayList<>();
}
return values.stream().map(value -> {
PointConfigCurveValueVo vo = new PointConfigCurveValueVo();
vo.setDataTime(value.getDataTime());
vo.setPointValue(value.getPointValue());
return vo;
}).collect(Collectors.toList());
}
private Date[] resolveTimeRange(PointConfigCurveRequest request) {
LocalDateTime end = LocalDateTime.now();
String rangeType = StringUtils.defaultIfBlank(request.getRangeType(), "day").toLowerCase(Locale.ROOT);
LocalDateTime start;
if ("custom".equals(rangeType)) {
if (StringUtils.isAnyBlank(request.getStartTime(), request.getEndTime())) {
throw new ServiceException("自定义时间范围必须传入开始时间和结束时间");
}
start = parseDateTime(request.getStartTime());
end = parseDateTime(request.getEndTime());
} else if ("week".equals(rangeType)) {
start = end.minusDays(7);
} else if ("month".equals(rangeType)) {
start = end.minusDays(30);
} else {
start = end.minusDays(1);
}
if (start.isAfter(end)) {
throw new ServiceException("开始时间不能晚于结束时间");
}
return new Date[]{
Timestamp.valueOf(start),
Timestamp.valueOf(end)
};
}
private LocalDateTime parseDateTime(String value) {
try {
return LocalDateTime.parse(value, DATETIME_FORMATTER);
} catch (DateTimeParseException ex) {
throw new ServiceException("时间格式错误,请使用 yyyy-MM-dd HH:mm:ss");
}
}
private void invalidatePointConfigCache(String siteId, String deviceId) {
if (StringUtils.isAnyBlank(siteId, deviceId)) {
return;
}
redisCache.deleteObject(RedisKeyConstants.POINT_CONFIG_DEVICE + siteId + "_" + deviceId);
}
private void invalidatePointConfigCacheBySite(String siteId) {
if (StringUtils.isBlank(siteId)) {
return;
}
Collection<String> keys = redisCache.keys(RedisKeyConstants.POINT_CONFIG_DEVICE + siteId + "_*");
if (keys != null && !keys.isEmpty()) {
redisCache.deleteObject(keys);
}
}
private JSONObject toJsonObject(Object raw) {
if (raw == null) {
return null;
}
if (raw instanceof JSONObject) {
return (JSONObject) raw;
}
try {
return JSON.parseObject(JSON.toJSONString(raw));
} catch (Exception ex) {
return null;
}
}
private JSONObject extractDataObject(JSONObject root) {
if (root == null) {
return null;
}
JSONObject dataObject = root.getJSONObject("Data");
if (dataObject != null) {
return dataObject;
}
String dataJson = root.getString("Data");
if (StringUtils.isBlank(dataJson)) {
return null;
}
try {
return JSON.parseObject(dataJson);
} catch (Exception ex) {
return null;
}
}
private Date extractDataTime(JSONObject root) {
if (root == null) {
return null;
}
Long timestamp = root.getLong("timestamp");
if (timestamp != null) {
return DateUtils.convertUpdateTime(timestamp);
}
return null;
}
private Object getValueIgnoreCase(JSONObject dataObject, String dataKey) {
if (dataObject == null || StringUtils.isBlank(dataKey)) {
return null;
}
Object directValue = dataObject.get(dataKey);
if (directValue != null) {
return directValue;
}
for (String key : dataObject.keySet()) {
if (key != null && key.equalsIgnoreCase(dataKey)) {
return dataObject.get(key);
}
}
return null;
}
private EmsPointConfig getPointConfig(String siteId,
String deviceId,
String dataKey,
Map<String, Map<String, EmsPointConfig>> configMapCache) {
if (StringUtils.isAnyBlank(siteId, deviceId, dataKey)) {
return null;
}
String cacheKey = siteId + "|" + deviceId;
Map<String, EmsPointConfig> configByKey = configMapCache.get(cacheKey);
if (configByKey == null) {
EmsPointConfig query = new EmsPointConfig();
query.setSiteId(siteId);
query.setDeviceId(deviceId);
List<EmsPointConfig> configList = emsPointConfigMapper.selectEmsPointConfigList(query);
configByKey = new HashMap<>();
if (configList != null) {
for (EmsPointConfig config : configList) {
if (config != null && StringUtils.isNotBlank(config.getDataKey())) {
configByKey.put(config.getDataKey().toUpperCase(Locale.ROOT), config);
}
}
}
configMapCache.put(cacheKey, configByKey);
}
return configByKey.get(dataKey.toUpperCase(Locale.ROOT));
}
private BigDecimal convertPointValue(BigDecimal sourceValue, EmsPointConfig pointConfig) {
if (sourceValue == null || pointConfig == null) {
return sourceValue;
}
BigDecimal a = pointConfig.getDataA() == null ? BigDecimal.ZERO : pointConfig.getDataA();
BigDecimal k = pointConfig.getDataK() == null ? BigDecimal.ONE : pointConfig.getDataK();
BigDecimal b = pointConfig.getDataB() == null ? BigDecimal.ZERO : pointConfig.getDataB();
return a.multiply(sourceValue).multiply(sourceValue)
.add(k.multiply(sourceValue))
.add(b);
}
private List<EmsPointConfig> parseCsv(MultipartFile file, String siteId) {
List<EmsPointConfig> result = new ArrayList<>();
try (BufferedReader reader = new BufferedReader(new InputStreamReader(file.getInputStream(), StandardCharsets.UTF_8))) {
String headerLine = reader.readLine();
if (StringUtils.isBlank(headerLine)) {
throw new ServiceException("CSV表头不能为空");
}
List<String> headerList = parseCsvLine(removeUtf8Bom(headerLine));
Map<String, Integer> headerIndex = buildHeaderIndex(headerList);
assertRequiredHeader(headerIndex, "device_category", "device_category");
assertRequiredHeader(headerIndex, "device_id", "device_id");
assertRequiredHeader(headerIndex, "data_key", "data_key");
assertRequiredHeader(headerIndex, "point_desc", "point_desc");
String line;
int lineNo = 1;
while ((line = reader.readLine()) != null) {
lineNo++;
if (StringUtils.isBlank(line)) {
continue;
}
List<String> valueList = parseCsvLine(line);
EmsPointConfig pointConfig = new EmsPointConfig();
pointConfig.setSiteId(siteId);
pointConfig.setDeviceCategory(getRequiredString(valueList, headerIndex, "device_category", lineNo));
pointConfig.setDeviceId(getRequiredString(valueList, headerIndex, "device_id", lineNo));
pointConfig.setDataKey(getRequiredString(valueList, headerIndex, "data_key", lineNo));
pointConfig.setPointDesc(getRequiredString(valueList, headerIndex, "point_desc", lineNo));
String registerAddress = getString(valueList, headerIndex, "register_address");
pointConfig.setRegisterAddress(StringUtils.isBlank(registerAddress) ? "" : registerAddress);
pointConfig.setPointName(getString(valueList, headerIndex, "point_name"));
pointConfig.setDataUnit(getString(valueList, headerIndex, "data_unit"));
pointConfig.setDataA(getDecimal(valueList, headerIndex, "data_a", lineNo));
pointConfig.setDataK(getDecimal(valueList, headerIndex, "data_k", lineNo));
pointConfig.setDataB(getDecimal(valueList, headerIndex, "data_b", lineNo));
pointConfig.setDataBit(getInteger(valueList, headerIndex, "data_bit", lineNo));
pointConfig.setIsAlarm(getInteger(valueList, headerIndex, "is_alarm", lineNo));
pointConfig.setPointType(getString(valueList, headerIndex, "point_type"));
pointConfig.setCalcExpression(getString(valueList, headerIndex, "calc_expression"));
pointConfig.setRemark(getString(valueList, headerIndex, "remark"));
normalizeAndValidatePointConfig(pointConfig);
result.add(pointConfig);
}
} catch (IOException e) {
throw new ServiceException("CSV读取失败: " + e.getMessage());
}
return result;
}
private void assertRequiredHeader(Map<String, Integer> headerIndex, String headerKey, String headerName) {
if (!headerIndex.containsKey(headerKey)) {
throw new ServiceException("CSV缺少必填列: " + headerName);
}
}
private Map<String, Integer> buildHeaderIndex(List<String> headerList) {
Map<String, Integer> headerIndex = new HashMap<>();
for (int i = 0; i < headerList.size(); i++) {
String normalizedHeader = toCanonicalHeaderKey(headerList.get(i));
if (StringUtils.isBlank(normalizedHeader)) {
continue;
}
headerIndex.putIfAbsent(normalizedHeader, i);
}
return headerIndex;
}
private String getRequiredString(List<String> valueList, Map<String, Integer> headerIndex, String key, int lineNo) {
String value = getString(valueList, headerIndex, key);
if (StringUtils.isBlank(value)) {
throw new ServiceException(String.format("CSV第%d行字段[%s]不能为空", lineNo, key));
}
return value;
}
private String getString(List<String> valueList, Map<String, Integer> headerIndex, String key) {
Integer index = headerIndex.get(key);
if (index == null || index < 0 || index >= valueList.size()) {
return null;
}
String value = valueList.get(index);
return StringUtils.isBlank(value) ? null : value.trim();
}
private Integer getInteger(List<String> valueList, Map<String, Integer> headerIndex, String key, int lineNo) {
String value = getString(valueList, headerIndex, key);
if (StringUtils.isBlank(value)) {
return null;
}
if (!INTEGER_PATTERN.matcher(value).matches()) {
throw new ServiceException(String.format("CSV第%d行字段[%s]必须是整数", lineNo, key));
}
return Integer.parseInt(value);
}
private BigDecimal getDecimal(List<String> valueList, Map<String, Integer> headerIndex, String key, int lineNo) {
String value = getString(valueList, headerIndex, key);
if (StringUtils.isBlank(value)) {
return null;
}
if (!DECIMAL_PATTERN.matcher(value).matches()) {
throw new ServiceException(String.format("CSV第%d行字段[%s]必须是数字", lineNo, key));
}
return new BigDecimal(value);
}
private String removeUtf8Bom(String content) {
if (StringUtils.isBlank(content)) {
return content;
}
if (content.charAt(0) == '\ufeff') {
return content.substring(1);
}
return content;
}
private String normalizeHeader(String header) {
if (header == null) {
return "";
}
return header.trim().toLowerCase().replace("-", "_").replace(" ", "");
}
private String toCanonicalHeaderKey(String header) {
String normalized = normalizeHeader(header);
if (StringUtils.isBlank(normalized)) {
return "";
}
String compact = normalized.replace("_", "");
switch (compact) {
case "siteid":
case "站点id":
return "site_id";
case "devicecategory":
case "设备类型":
return "device_category";
case "deviceid":
case "设备id":
return "device_id";
case "pointname":
case "点位名称":
return "point_name";
case "datakey":
case "数据键":
return "data_key";
case "pointdesc":
case "点位描述":
return "point_desc";
case "registeraddress":
case "寄存器地址":
return "register_address";
case "dataunit":
case "datounit":
case "单位":
return "data_unit";
case "dataa":
case "datoa":
case "a系数":
return "data_a";
case "datak":
case "datok":
case "k系数":
return "data_k";
case "datab":
case "datob":
case "b系数":
return "data_b";
case "databit":
case "datobit":
case "位偏移":
return "data_bit";
case "isalarm":
case "报警点位":
return "is_alarm";
case "pointtype":
case "点位类型":
return "point_type";
case "calcexpression":
case "计算表达式":
return "calc_expression";
case "remark":
case "备注":
return "remark";
default:
return normalized;
}
}
private List<String> parseCsvLine(String line) {
List<String> result = new ArrayList<>();
if (line == null) {
return result;
}
StringBuilder current = new StringBuilder();
boolean inQuotes = false;
for (int i = 0; i < line.length(); i++) {
char c = line.charAt(i);
if (c == '"') {
if (inQuotes && i + 1 < line.length() && line.charAt(i + 1) == '"') {
current.append('"');
i++;
} else {
inQuotes = !inQuotes;
}
continue;
}
if (c == ',' && !inQuotes) {
result.add(current.toString());
current.setLength(0);
continue;
}
current.append(c);
}
result.add(current.toString());
return result;
}
private void normalizeAndValidatePointConfig(EmsPointConfig pointConfig) {
if (pointConfig == null) {
return;
}
pointConfig.setPointType(normalizePointType(pointConfig.getPointType()));
pointConfig.setCalcExpression(StringUtils.trimToNull(pointConfig.getCalcExpression()));
if ("calc".equals(pointConfig.getPointType())) {
if (StringUtils.isBlank(pointConfig.getCalcExpression())) {
throw new ServiceException("计算点必须填写计算表达式");
}
if (!CALC_EXPRESSION_PATTERN.matcher(pointConfig.getCalcExpression()).matches()) {
throw new ServiceException("计算表达式仅支持数字、字母、下划线、空格和四则运算符");
}
} else {
pointConfig.setCalcExpression(null);
}
}
private String normalizePointType(String pointType) {
String normalized = StringUtils.trimToEmpty(pointType).toLowerCase(Locale.ROOT);
if ("calc".equals(normalized) || "calculate".equals(normalized) || "计算点".equals(normalized)) {
return "calc";
}
return "data";
}
}

View File

@ -0,0 +1,231 @@
<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE mapper
PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
"http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="com.xzzn.ems.mapper.EmsPointConfigMapper">
<resultMap type="EmsPointConfig" id="EmsPointConfigResult">
<result property="id" column="id"/>
<result property="siteId" column="site_id"/>
<result property="deviceCategory" column="device_category"/>
<result property="deviceId" column="device_id"/>
<result property="pointName" column="point_name"/>
<result property="dataKey" column="data_key"/>
<result property="pointDesc" column="point_desc"/>
<result property="registerAddress" column="register_address"/>
<result property="dataUnit" column="data_unit"/>
<result property="dataA" column="data_a"/>
<result property="dataK" column="data_k"/>
<result property="dataB" column="data_b"/>
<result property="dataBit" column="data_bit"/>
<result property="isAlarm" column="is_alarm"/>
<result property="pointType" column="point_type"/>
<result property="calcExpression" column="calc_expression"/>
<result property="createBy" column="create_by"/>
<result property="createTime" column="create_time"/>
<result property="updateBy" column="update_by"/>
<result property="updateTime" column="update_time"/>
<result property="remark" column="remark"/>
</resultMap>
<sql id="selectEmsPointConfigVo">
select id, site_id, device_category, device_id, point_name, data_key, point_desc, register_address,
data_unit, data_a, data_k, data_b, data_bit, is_alarm, point_type, calc_expression,
create_by, create_time, update_by, update_time, remark
from ems_point_config
</sql>
<select id="selectEmsPointConfigById" parameterType="Long" resultMap="EmsPointConfigResult">
<include refid="selectEmsPointConfigVo"/>
where id = #{id}
</select>
<select id="selectEmsPointConfigList" parameterType="EmsPointConfig" resultMap="EmsPointConfigResult">
<include refid="selectEmsPointConfigVo"/>
<where>
<if test="siteId != null and siteId != ''">and site_id = #{siteId}</if>
<if test="deviceCategory != null and deviceCategory != ''">and device_category = #{deviceCategory}</if>
<if test="deviceId != null and deviceId != ''">and device_id = #{deviceId}</if>
<if test="dataKey != null and dataKey != ''">and data_key like concat('%', #{dataKey}, '%')</if>
<if test="pointDesc != null and pointDesc != ''">and point_desc like concat('%', #{pointDesc}, '%')</if>
<if test="pointType != null and pointType != ''">and point_type = #{pointType}</if>
<if test="registerAddress != null and registerAddress != ''">and register_address = #{registerAddress}</if>
</where>
order by update_time desc, id desc
</select>
<insert id="insertEmsPointConfig" parameterType="EmsPointConfig" useGeneratedKeys="true" keyProperty="id">
insert into ems_point_config
<trim prefix="(" suffix=")" suffixOverrides=",">
<if test="siteId != null">site_id,</if>
<if test="deviceCategory != null">device_category,</if>
<if test="deviceId != null">device_id,</if>
<if test="pointName != null">point_name,</if>
<if test="dataKey != null">data_key,</if>
<if test="pointDesc != null">point_desc,</if>
<if test="registerAddress != null">register_address,</if>
<if test="dataUnit != null">data_unit,</if>
<if test="dataA != null">data_a,</if>
<if test="dataK != null">data_k,</if>
<if test="dataB != null">data_b,</if>
<if test="dataBit != null">data_bit,</if>
<if test="isAlarm != null">is_alarm,</if>
<if test="pointType != null">point_type,</if>
<if test="calcExpression != null">calc_expression,</if>
<if test="createBy != null">create_by,</if>
<if test="createTime != null">create_time,</if>
<if test="updateBy != null">update_by,</if>
<if test="updateTime != null">update_time,</if>
<if test="remark != null">remark,</if>
</trim>
<trim prefix="values (" suffix=")" suffixOverrides=",">
<if test="siteId != null">#{siteId},</if>
<if test="deviceCategory != null">#{deviceCategory},</if>
<if test="deviceId != null">#{deviceId},</if>
<if test="pointName != null">#{pointName},</if>
<if test="dataKey != null">#{dataKey},</if>
<if test="pointDesc != null">#{pointDesc},</if>
<if test="registerAddress != null">#{registerAddress},</if>
<if test="dataUnit != null">#{dataUnit},</if>
<if test="dataA != null">#{dataA},</if>
<if test="dataK != null">#{dataK},</if>
<if test="dataB != null">#{dataB},</if>
<if test="dataBit != null">#{dataBit},</if>
<if test="isAlarm != null">#{isAlarm},</if>
<if test="pointType != null">#{pointType},</if>
<if test="calcExpression != null">#{calcExpression},</if>
<if test="createBy != null">#{createBy},</if>
<if test="createTime != null">#{createTime},</if>
<if test="updateBy != null">#{updateBy},</if>
<if test="updateTime != null">#{updateTime},</if>
<if test="remark != null">#{remark},</if>
</trim>
</insert>
<update id="updateEmsPointConfig" parameterType="EmsPointConfig">
update ems_point_config
<trim prefix="SET" suffixOverrides=",">
<if test="siteId != null">site_id = #{siteId},</if>
<if test="deviceCategory != null">device_category = #{deviceCategory},</if>
<if test="deviceId != null">device_id = #{deviceId},</if>
<if test="pointName != null">point_name = #{pointName},</if>
<if test="dataKey != null">data_key = #{dataKey},</if>
<if test="pointDesc != null">point_desc = #{pointDesc},</if>
<if test="registerAddress != null">register_address = #{registerAddress},</if>
<if test="dataUnit != null">data_unit = #{dataUnit},</if>
<if test="dataA != null">data_a = #{dataA},</if>
<if test="dataK != null">data_k = #{dataK},</if>
<if test="dataB != null">data_b = #{dataB},</if>
<if test="dataBit != null">data_bit = #{dataBit},</if>
<if test="isAlarm != null">is_alarm = #{isAlarm},</if>
<if test="pointType != null">point_type = #{pointType},</if>
<if test="calcExpression != null">calc_expression = #{calcExpression},</if>
<if test="updateBy != null">update_by = #{updateBy},</if>
<if test="updateTime != null">update_time = #{updateTime},</if>
<if test="remark != null">remark = #{remark},</if>
</trim>
where id = #{id}
</update>
<delete id="deleteEmsPointConfigById" parameterType="Long">
delete from ems_point_config where id = #{id}
</delete>
<delete id="deleteEmsPointConfigByIds" parameterType="String">
delete from ems_point_config where id in
<foreach item="id" collection="array" open="(" separator="," close=")">
#{id}
</foreach>
</delete>
<select id="countBySiteId" resultType="int">
select count(1)
from ems_point_config
where site_id = #{siteId}
</select>
<delete id="deleteBySiteId">
delete from ems_point_config
where site_id = #{siteId}
</delete>
<insert id="copyTemplateToSite">
insert into ems_point_config (
site_id, device_category, device_id, point_name, data_key, point_desc, register_address,
data_unit, data_a, data_k, data_b, data_bit, is_alarm, point_type, calc_expression,
create_by, create_time, update_by, update_time, remark
)
select
#{targetSiteId}, device_category, device_id, point_name, data_key, point_desc, register_address,
data_unit, data_a, data_k, data_b, data_bit, is_alarm, point_type, calc_expression,
#{operName}, now(), #{operName}, now(), remark
from ems_point_config
where site_id = #{templateSiteId}
</insert>
<select id="getRegisterAddress" resultType="java.lang.String">
select register_address
from ems_point_config
where site_id = #{siteId}
and device_category = #{deviceCategory}
and device_id = #{deviceId}
and data_key = #{dataKey}
limit 1
</select>
<select id="getPointNameList" resultType="com.xzzn.ems.domain.vo.GeneralQueryPointOptionVo">
select point_name as pointName,
data_key as dataKey,
point_desc as pointDesc
from ems_point_config
where 1 = 1
<if test="siteIds != null and siteIds.size() > 0">
and site_id in
<foreach collection="siteIds" item="siteId" open="(" separator="," close=")">
#{siteId}
</foreach>
</if>
<if test="deviceCategory != null and deviceCategory != ''">
and device_category = #{deviceCategory}
</if>
<if test="deviceId != null and deviceId != ''">
and device_id = #{deviceId}
</if>
<if test="pointName != null and pointName != ''">
and (
point_name like concat('%', #{pointName}, '%')
or data_key like concat('%', #{pointName}, '%')
or point_desc like concat('%', #{pointName}, '%')
)
</if>
group by point_name, data_key, point_desc
order by point_name asc, data_key asc
</select>
<select id="getConfigListForGeneralQuery" resultMap="EmsPointConfigResult">
<include refid="selectEmsPointConfigVo"/>
where 1 = 1
<if test="siteIds != null and siteIds.size() > 0">
and site_id in
<foreach collection="siteIds" item="siteId" open="(" separator="," close=")">
#{siteId}
</foreach>
</if>
<if test="deviceCategory != null and deviceCategory != ''">
and device_category = #{deviceCategory}
</if>
<if test="pointNames != null and pointNames.size() > 0">
and point_name in
<foreach collection="pointNames" item="pointName" open="(" separator="," close=")">
#{pointName}
</foreach>
</if>
<if test="deviceIds != null and deviceIds.size() > 0">
and device_id in
<foreach collection="deviceIds" item="deviceId" open="(" separator="," close=")">
#{deviceId}
</foreach>
</if>
</select>
</mapper>

View File

@ -0,0 +1,40 @@
<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE mapper
PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
"http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="com.xzzn.ems.mapper.EmsSiteMonitorDataMapper">
<select id="selectHistoryJsonByMinute" resultType="java.lang.String">
select data_json
from ${tableName}
where site_id = #{siteId}
and statis_minute = #{statisMinute}
limit 1
</select>
<insert id="upsertHistoryJsonByMinute">
insert into ${tableName} (
site_id, statis_minute, data_json, create_by, create_time, update_by, update_time
) values (
#{siteId}, #{statisMinute}, #{dataJson}, #{operName}, now(), #{operName}, now()
)
on duplicate key update
data_json = values(data_json),
update_by = values(update_by),
update_time = now()
</insert>
<update id="updateHistoryHotColumns">
update ${tableName}
set hot_soc = #{hotSoc},
hot_total_active_power = #{hotTotalActivePower},
hot_total_reactive_power = #{hotTotalReactivePower},
hot_day_charged_cap = #{hotDayChargedCap},
hot_day_dis_charged_cap = #{hotDayDisChargedCap},
update_by = #{operName},
update_time = now()
where site_id = #{siteId}
and statis_minute = #{statisMinute}
</update>
</mapper>

View File

@ -0,0 +1,33 @@
<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE mapper
PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
"http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="com.xzzn.ems.mapper.EmsSiteMonitorItemMapper">
<resultMap id="EmsSiteMonitorItemResult" type="com.xzzn.ems.domain.EmsSiteMonitorItem">
<result property="id" column="id"/>
<result property="moduleCode" column="module_code"/>
<result property="moduleName" column="module_name"/>
<result property="menuCode" column="menu_code"/>
<result property="menuName" column="menu_name"/>
<result property="sectionName" column="section_name"/>
<result property="fieldCode" column="field_code"/>
<result property="fieldName" column="field_name"/>
<result property="sortNo" column="sort_no"/>
<result property="status" column="status"/>
<result property="createBy" column="create_by"/>
<result property="createTime" column="create_time"/>
<result property="updateBy" column="update_by"/>
<result property="updateTime" column="update_time"/>
<result property="remark" column="remark"/>
</resultMap>
<select id="selectEnabledList" resultMap="EmsSiteMonitorItemResult">
select id, module_code, module_name, menu_code, menu_name, section_name, field_code, field_name, sort_no, status,
create_by, create_time, update_by, update_time, remark
from ems_site_monitor_item
where status = 1
order by sort_no asc, id asc
</select>
</mapper>

View File

@ -0,0 +1,40 @@
<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE mapper
PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
"http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="com.xzzn.ems.mapper.EmsSiteMonitorPointMatchMapper">
<resultMap id="EmsSiteMonitorPointMatchResult" type="com.xzzn.ems.domain.EmsSiteMonitorPointMatch">
<result property="id" column="id"/>
<result property="siteId" column="site_id"/>
<result property="fieldCode" column="field_code"/>
<result property="dataPoint" column="data_point"/>
<result property="createBy" column="create_by"/>
<result property="createTime" column="create_time"/>
<result property="updateBy" column="update_by"/>
<result property="updateTime" column="update_time"/>
<result property="remark" column="remark"/>
</resultMap>
<select id="selectBySiteId" resultMap="EmsSiteMonitorPointMatchResult">
select id, site_id, field_code, data_point, create_by, create_time, update_by, update_time, remark
from ems_site_monitor_point_match
where site_id = #{siteId}
order by id asc
</select>
<delete id="deleteBySiteId">
delete from ems_site_monitor_point_match
where site_id = #{siteId}
</delete>
<insert id="insertBatch">
insert into ems_site_monitor_point_match
(site_id, field_code, data_point, create_by, create_time, update_by, update_time)
values
<foreach collection="list" item="item" separator=",">
(#{item.siteId}, #{item.fieldCode}, #{item.dataPoint}, #{item.createBy}, now(), #{item.updateBy}, now())
</foreach>
</insert>
</mapper>