feat(event): 添加暂态事件波形查看与导出功能
- 新增 getTransientEventWave 接口用于查看暂态事件波形 - 新增 exportTransientEventWaves 接口用于批量导出暂态事件波形 - 添加 EventWaveExportParam 参数类支持波形导出 - 在 EventListMapper 中增加 selectTransientDetailsByIds 查询方法 - 更新事件列表查询参数支持毫秒级时间格式 - 移除事件描述模糊查询条件优化查询性能 - 添加波形导出相关的常量和工具类集成
This commit is contained in:
@@ -50,10 +50,10 @@ webSocket:
|
|||||||
|
|
||||||
steady:
|
steady:
|
||||||
influxdb:
|
influxdb:
|
||||||
url: http://192.168.1.103:18086
|
url: http://192.168.1.68:18086
|
||||||
database: pqsbase
|
database: pqsbase
|
||||||
username: admin
|
username: admin
|
||||||
password: ${STEADY_INFLUXDB_PASSWORD:}
|
password: 123456
|
||||||
ssl: false
|
ssl: false
|
||||||
connect-timeout-ms: 5000
|
connect-timeout-ms: 5000
|
||||||
read-timeout-ms: 30000
|
read-timeout-ms: 30000
|
||||||
|
|||||||
@@ -40,34 +40,29 @@ public class SteadyInfluxQueryComponent {
|
|||||||
private final SteadyInfluxDbProperties properties;
|
private final SteadyInfluxDbProperties properties;
|
||||||
|
|
||||||
public List<SteadyTrendPointVO> queryTrendPoints(SteadyTrendResolvedFieldBO field, LocalDateTime startTime,
|
public List<SteadyTrendPointVO> queryTrendPoints(SteadyTrendResolvedFieldBO field, LocalDateTime startTime,
|
||||||
LocalDateTime endTime, String bucket, Integer qualityFlag) {
|
LocalDateTime endTime, Integer qualityFlag) {
|
||||||
validateConfig();
|
validateConfig();
|
||||||
String query = buildTrendQuery(field, startTime, endTime, bucket, qualityFlag);
|
String query = buildTrendQuery(field, startTime, endTime, qualityFlag);
|
||||||
String body = executeQuery(query);
|
String body = executeQuery(query);
|
||||||
return parseTrendPoints(body);
|
return parseTrendPoints(body);
|
||||||
}
|
}
|
||||||
|
|
||||||
public String buildTrendQuery(SteadyTrendResolvedFieldBO field, LocalDateTime startTime, LocalDateTime endTime,
|
public String buildTrendQuery(SteadyTrendResolvedFieldBO field, LocalDateTime startTime, LocalDateTime endTime,
|
||||||
String bucket, Integer qualityFlag) {
|
Integer qualityFlag) {
|
||||||
StringBuilder sql = new StringBuilder();
|
StringBuilder sql = new StringBuilder();
|
||||||
if (bucket == null || bucket.trim().isEmpty()) {
|
sql.append("SELECT \"").append(field.getField()).append("\" AS \"value\"");
|
||||||
sql.append("SELECT \"").append(field.getField()).append("\" AS \"value\"");
|
|
||||||
} else {
|
|
||||||
sql.append("SELECT mean(\"").append(field.getField()).append("\") AS \"value\"");
|
|
||||||
}
|
|
||||||
sql.append(" FROM \"").append(field.getMeasurement()).append("\"");
|
sql.append(" FROM \"").append(field.getMeasurement()).append("\"");
|
||||||
sql.append(" WHERE time >= '").append(INFLUX_TIME_FORMATTER.format(startTime)).append("'");
|
sql.append(" WHERE time >= '").append(INFLUX_TIME_FORMATTER.format(startTime)).append("'");
|
||||||
sql.append(" AND time <= '").append(INFLUX_TIME_FORMATTER.format(endTime)).append("'");
|
sql.append(" AND time <= '").append(INFLUX_TIME_FORMATTER.format(endTime)).append("'");
|
||||||
sql.append(" AND \"LINEID\" = '").append(escapeTagValue(field.getLineId())).append("'");
|
sql.append(" AND \"line_id\" = '").append(escapeTagValue(field.getLineId())).append("'");
|
||||||
sql.append(" AND \"PHASIC_TYPE\" = '").append(escapeTagValue(field.getPhase())).append("'");
|
sql.append(" AND \"phasic_type\" = '").append(escapeTagValue(field.getPhase())).append("'");
|
||||||
|
if (hasValueTypeTag(field.getMeasurement())) {
|
||||||
|
sql.append(" AND \"value_type\" = '").append(resolveValueType(field.getStatType())).append("'");
|
||||||
|
}
|
||||||
if (qualityFlag != null) {
|
if (qualityFlag != null) {
|
||||||
sql.append(" AND \"QUALITYFLAG\" = '").append(qualityFlag).append("'");
|
sql.append(" AND \"quality_flag\" = '").append(qualityFlag).append("'");
|
||||||
}
|
|
||||||
if (bucket != null && !bucket.trim().isEmpty()) {
|
|
||||||
sql.append(" GROUP BY time(").append(bucket.trim()).append(") fill(none)");
|
|
||||||
} else {
|
|
||||||
sql.append(" ORDER BY time ASC");
|
|
||||||
}
|
}
|
||||||
|
sql.append(" ORDER BY time ASC");
|
||||||
return sql.toString();
|
return sql.toString();
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -165,6 +160,17 @@ public class SteadyInfluxQueryComponent {
|
|||||||
return value == null ? "" : value.replace("\\", "\\\\").replace("'", "\\'");
|
return value == null ? "" : value.replace("\\", "\\\\").replace("'", "\\'");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private String resolveValueType(String statType) {
|
||||||
|
if (statType == null || statType.trim().isEmpty()) {
|
||||||
|
return "AVG";
|
||||||
|
}
|
||||||
|
return statType.trim().toUpperCase();
|
||||||
|
}
|
||||||
|
|
||||||
|
private boolean hasValueTypeTag(String measurement) {
|
||||||
|
return !"data_flicker".equals(measurement) && !"data_fluc".equals(measurement) && !"data_plt".equals(measurement);
|
||||||
|
}
|
||||||
|
|
||||||
private String trimRightSlash(String value) {
|
private String trimRightSlash(String value) {
|
||||||
String text = value.trim();
|
String text = value.trim();
|
||||||
while (text.endsWith("/")) {
|
while (text.endsWith("/")) {
|
||||||
|
|||||||
@@ -6,8 +6,6 @@ import com.njcn.gather.steady.datavie.pojo.bo.SteadyTrendIndicatorDefinitionBO;
|
|||||||
import com.njcn.gather.steady.datavie.pojo.bo.SteadyTrendResolvedFieldBO;
|
import com.njcn.gather.steady.datavie.pojo.bo.SteadyTrendResolvedFieldBO;
|
||||||
import com.njcn.gather.steady.datavie.pojo.bo.SteadyTrendSeriesFieldBO;
|
import com.njcn.gather.steady.datavie.pojo.bo.SteadyTrendSeriesFieldBO;
|
||||||
import com.njcn.gather.steady.datavie.pojo.param.SteadyTrendQueryParam;
|
import com.njcn.gather.steady.datavie.pojo.param.SteadyTrendQueryParam;
|
||||||
import com.njcn.gather.tool.adddata.component.AddDataTableRegistry;
|
|
||||||
import com.njcn.gather.tool.adddata.pojo.bo.AddDataTableDefinition;
|
|
||||||
import lombok.RequiredArgsConstructor;
|
import lombok.RequiredArgsConstructor;
|
||||||
import org.springframework.stereotype.Component;
|
import org.springframework.stereotype.Component;
|
||||||
|
|
||||||
@@ -32,7 +30,6 @@ public class SteadyTrendFieldResolver {
|
|||||||
private static final DateTimeFormatter TIME_FORMATTER = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss");
|
private static final DateTimeFormatter TIME_FORMATTER = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss");
|
||||||
|
|
||||||
private final SteadyTrendIndicatorCatalog indicatorCatalog;
|
private final SteadyTrendIndicatorCatalog indicatorCatalog;
|
||||||
private final AddDataTableRegistry addDataTableRegistry;
|
|
||||||
|
|
||||||
public List<SteadyTrendResolvedFieldBO> resolveFields(SteadyTrendQueryParam param) {
|
public List<SteadyTrendResolvedFieldBO> resolveFields(SteadyTrendQueryParam param) {
|
||||||
validateBasicParam(param);
|
validateBasicParam(param);
|
||||||
@@ -80,9 +77,7 @@ public class SteadyTrendFieldResolver {
|
|||||||
}
|
}
|
||||||
List<SteadyTrendResolvedFieldBO> result = new ArrayList<SteadyTrendResolvedFieldBO>();
|
List<SteadyTrendResolvedFieldBO> result = new ArrayList<SteadyTrendResolvedFieldBO>();
|
||||||
for (SteadyTrendSeriesFieldBO seriesField : indicator.getSeriesFields()) {
|
for (SteadyTrendSeriesFieldBO seriesField : indicator.getSeriesFields()) {
|
||||||
String field = resolveStatField(seriesField.getField(), statType);
|
result.add(buildResolvedField(lineId, indicator, phase, statType, seriesField.getField(), seriesField.getName()));
|
||||||
validateColumn(indicator.getTableName(), field);
|
|
||||||
result.add(buildResolvedField(lineId, indicator, phase, statType, field, seriesField.getName()));
|
|
||||||
}
|
}
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
@@ -101,9 +96,7 @@ public class SteadyTrendFieldResolver {
|
|||||||
if (order < indicator.getHarmonicOrderStart() || order > indicator.getHarmonicOrderEnd()) {
|
if (order < indicator.getHarmonicOrderStart() || order > indicator.getHarmonicOrderEnd()) {
|
||||||
throw fail("谐波次数只能在 " + indicator.getHarmonicOrderStart() + " 到 " + indicator.getHarmonicOrderEnd() + " 之间");
|
throw fail("谐波次数只能在 " + indicator.getHarmonicOrderStart() + " 到 " + indicator.getHarmonicOrderEnd() + " 之间");
|
||||||
}
|
}
|
||||||
String baseField = indicator.getHarmonicFieldPrefix() + "_" + order;
|
String field = indicator.getHarmonicFieldPrefix() + "_" + order;
|
||||||
String field = resolveStatField(baseField, statType);
|
|
||||||
validateColumn(indicator.getTableName(), field);
|
|
||||||
result.add(buildResolvedField(lineId, indicator, phase, statType, field, order + "次" + indicator.getName()));
|
result.add(buildResolvedField(lineId, indicator, phase, statType, field, order + "次" + indicator.getName()));
|
||||||
}
|
}
|
||||||
return result;
|
return result;
|
||||||
@@ -177,25 +170,6 @@ public class SteadyTrendFieldResolver {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private String resolveStatField(String baseField, String statType) {
|
|
||||||
if ("AVG".equals(statType)) {
|
|
||||||
return baseField;
|
|
||||||
}
|
|
||||||
return baseField + "_" + statType;
|
|
||||||
}
|
|
||||||
|
|
||||||
private void validateColumn(String tableName, String field) {
|
|
||||||
AddDataTableDefinition definition;
|
|
||||||
try {
|
|
||||||
definition = addDataTableRegistry.getDefinition(tableName);
|
|
||||||
} catch (IllegalArgumentException ex) {
|
|
||||||
throw fail("稳态数据表不支持:" + tableName);
|
|
||||||
}
|
|
||||||
if (!definition.getColumns().contains(field)) {
|
|
||||||
throw fail("稳态趋势字段不支持:" + tableName + "." + field);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private List<String> normalizeTextList(List<String> values) {
|
private List<String> normalizeTextList(List<String> values) {
|
||||||
if (values == null || values.isEmpty()) {
|
if (values == null || values.isEmpty()) {
|
||||||
return new ArrayList<String>();
|
return new ArrayList<String>();
|
||||||
|
|||||||
@@ -28,32 +28,31 @@ public class SteadyTrendIndicatorCatalog {
|
|||||||
public SteadyTrendIndicatorCatalog() {
|
public SteadyTrendIndicatorCatalog() {
|
||||||
List<SteadyTrendIndicatorDefinitionBO> result = new ArrayList<SteadyTrendIndicatorDefinitionBO>();
|
List<SteadyTrendIndicatorDefinitionBO> result = new ArrayList<SteadyTrendIndicatorDefinitionBO>();
|
||||||
result.add(indicator("V_RMS", "相电压有效值", "VOLTAGE", "电压趋势", "data_v", ABC_PHASES,
|
result.add(indicator("V_RMS", "相电压有效值", "VOLTAGE", "电压趋势", "data_v", ABC_PHASES,
|
||||||
fields(field("RMS", "相电压有效值")), FULL_STATS, "V"));
|
fields(field("rms", "相电压有效值")), FULL_STATS, "V"));
|
||||||
result.add(indicator("V_LINE_RMS", "线电压有效值", "VOLTAGE", "电压趋势", "data_v", T_PHASE,
|
result.add(indicator("V_LINE_RMS", "线电压有效值", "VOLTAGE", "电压趋势", "data_v", T_PHASE,
|
||||||
fields(field("RMSAB", "AB线电压"), field("RMSBC", "BC线电压"), field("RMSCA", "CA线电压")),
|
fields(field("rms_lvr", "线电压有效值")),
|
||||||
FULL_STATS, "V"));
|
FULL_STATS, "V"));
|
||||||
result.add(indicator("FREQ", "频率", "FREQUENCY", "频率趋势", "data_v", T_PHASE,
|
result.add(indicator("FREQ", "频率", "FREQUENCY", "频率趋势", "data_v", T_PHASE,
|
||||||
fields(field("FREQ", "频率")), FULL_STATS, "Hz"));
|
fields(field("freq", "频率")), FULL_STATS, "Hz"));
|
||||||
result.add(indicator("V_THD", "电压总谐波畸变率", "HARMONIC", "谐波趋势", "data_v", ABC_PHASES,
|
result.add(indicator("V_THD", "电压总谐波畸变率", "HARMONIC", "谐波趋势", "data_v", ABC_PHASES,
|
||||||
fields(field("V_THD", "电压总谐波畸变率")), FULL_STATS, "%"));
|
fields(field("v_thd", "电压总谐波畸变率")), FULL_STATS, "%"));
|
||||||
result.add(indicator("I_RMS", "电流有效值", "CURRENT", "电流趋势", "data_i", ABC_PHASES,
|
result.add(indicator("I_RMS", "电流有效值", "CURRENT", "电流趋势", "data_i", ABC_PHASES,
|
||||||
fields(field("RMS", "电流有效值")), FULL_STATS, "A"));
|
fields(field("rms", "电流有效值")), FULL_STATS, "A"));
|
||||||
result.add(indicator("I_THD", "电流总谐波畸变率", "HARMONIC", "谐波趋势", "data_i", ABC_PHASES,
|
result.add(indicator("I_THD", "电流总谐波畸变率", "HARMONIC", "谐波趋势", "data_i", ABC_PHASES,
|
||||||
fields(field("I_THD", "电流总谐波畸变率")), FULL_STATS, "%"));
|
fields(field("i_thd", "电流总谐波畸变率")), FULL_STATS, "%"));
|
||||||
result.add(harmonic("V_HARMONIC", "电压谐波幅值", "data_harmphasic_v", "V", "V"));
|
result.add(harmonic("V_HARMONIC", "电压谐波幅值", "data_harmphasic_v", "v", "V"));
|
||||||
result.add(harmonic("I_HARMONIC", "电流谐波幅值", "data_harmphasic_i", "I", "A"));
|
result.add(harmonic("I_HARMONIC", "电流谐波幅值", "data_harmphasic_i", "i", "A"));
|
||||||
result.add(harmonic("V_HARMONIC_RATE", "电压谐波含有率", "data_harmrate_v", "V", "%"));
|
result.add(harmonic("V_HARMONIC_RATE", "电压谐波含有率", "data_harmrate_v", "v", "%"));
|
||||||
result.add(harmonic("I_HARMONIC_RATE", "电流谐波含有率", "data_harmrate_i", "I", "%"));
|
result.add(harmonic("I_INTER_HARMONIC", "间谐波电流", "data_inharm_i", "i", "A"));
|
||||||
result.add(harmonic("I_INTER_HARMONIC", "间谐波电流", "data_inharm_i", "I", "A"));
|
result.add(harmonicPower("P_HARMONIC_POWER", "有功谐波功率", "data_harmpower_p", "p", "kW"));
|
||||||
result.add(harmonicPower("P_HARMONIC_POWER", "有功谐波功率", "data_harmpower_p", "P", "kW"));
|
result.add(harmonicPower("Q_HARMONIC_POWER", "无功谐波功率", "data_harmpower_q", "q", "kvar"));
|
||||||
result.add(harmonicPower("Q_HARMONIC_POWER", "无功谐波功率", "data_harmpower_q", "Q", "kvar"));
|
result.add(harmonicPower("S_HARMONIC_POWER", "视在谐波功率", "data_harmpower_s", "s", "kVA"));
|
||||||
result.add(harmonicPower("S_HARMONIC_POWER", "视在谐波功率", "data_harmpower_s", "S", "kVA"));
|
|
||||||
result.add(indicator("FLUC", "电压波动", "FLICKER", "闪变趋势", "data_fluc", T_PHASE,
|
result.add(indicator("FLUC", "电压波动", "FLICKER", "闪变趋势", "data_fluc", T_PHASE,
|
||||||
fields(field("FLUC", "电压波动")), AVG_ONLY, "%"));
|
fields(field("fluc", "电压波动")), AVG_ONLY, "%"));
|
||||||
result.add(indicator("PST", "短时闪变", "FLICKER", "闪变趋势", "data_flicker", T_PHASE,
|
result.add(indicator("PST", "短时闪变", "FLICKER", "闪变趋势", "data_flicker", T_PHASE,
|
||||||
fields(field("PST", "短时闪变")), AVG_ONLY, ""));
|
fields(field("pst", "短时闪变")), AVG_ONLY, ""));
|
||||||
result.add(indicator("PLT", "长时闪变", "FLICKER", "闪变趋势", "data_plt", T_PHASE,
|
result.add(indicator("PLT", "长时闪变", "FLICKER", "闪变趋势", "data_plt", T_PHASE,
|
||||||
fields(field("PLT", "长时闪变")), AVG_ONLY, ""));
|
fields(field("plt", "长时闪变")), AVG_ONLY, ""));
|
||||||
indicators = Collections.unmodifiableList(result);
|
indicators = Collections.unmodifiableList(result);
|
||||||
|
|
||||||
Map<String, SteadyTrendIndicatorDefinitionBO> map = new LinkedHashMap<String, SteadyTrendIndicatorDefinitionBO>();
|
Map<String, SteadyTrendIndicatorDefinitionBO> map = new LinkedHashMap<String, SteadyTrendIndicatorDefinitionBO>();
|
||||||
|
|||||||
@@ -29,9 +29,6 @@ public class SteadyTrendQueryParam {
|
|||||||
@ApiModelProperty("结束时间,格式 yyyy-MM-dd HH:mm:ss")
|
@ApiModelProperty("结束时间,格式 yyyy-MM-dd HH:mm:ss")
|
||||||
private String timeEnd;
|
private String timeEnd;
|
||||||
|
|
||||||
@ApiModelProperty("分桶粒度,如 1m、5m、10m、30m、1h")
|
|
||||||
private String bucket;
|
|
||||||
|
|
||||||
@ApiModelProperty("质量标识")
|
@ApiModelProperty("质量标识")
|
||||||
private Integer qualityFlag;
|
private Integer qualityFlag;
|
||||||
|
|
||||||
|
|||||||
@@ -18,8 +18,6 @@ public class SteadyTrendQueryVO implements Serializable {
|
|||||||
|
|
||||||
private Boolean sampled;
|
private Boolean sampled;
|
||||||
|
|
||||||
private String bucket;
|
|
||||||
|
|
||||||
private Integer sourcePointCount;
|
private Integer sourcePointCount;
|
||||||
|
|
||||||
private Integer displayPointCount;
|
private Integer displayPointCount;
|
||||||
|
|||||||
@@ -1,7 +1,5 @@
|
|||||||
package com.njcn.gather.steady.datavie.service.impl;
|
package com.njcn.gather.steady.datavie.service.impl;
|
||||||
|
|
||||||
import com.njcn.common.pojo.enums.response.CommonResponseEnum;
|
|
||||||
import com.njcn.common.pojo.exception.BusinessException;
|
|
||||||
import com.njcn.gather.steady.datavie.component.SteadyInfluxQueryComponent;
|
import com.njcn.gather.steady.datavie.component.SteadyInfluxQueryComponent;
|
||||||
import com.njcn.gather.steady.datavie.component.SteadyTrendFieldResolver;
|
import com.njcn.gather.steady.datavie.component.SteadyTrendFieldResolver;
|
||||||
import com.njcn.gather.steady.datavie.pojo.bo.SteadyTrendResolvedFieldBO;
|
import com.njcn.gather.steady.datavie.pojo.bo.SteadyTrendResolvedFieldBO;
|
||||||
@@ -21,7 +19,6 @@ import java.math.BigDecimal;
|
|||||||
import java.math.RoundingMode;
|
import java.math.RoundingMode;
|
||||||
import java.time.LocalDate;
|
import java.time.LocalDate;
|
||||||
import java.time.LocalDateTime;
|
import java.time.LocalDateTime;
|
||||||
import java.time.temporal.ChronoUnit;
|
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
import java.util.Collections;
|
import java.util.Collections;
|
||||||
import java.util.Comparator;
|
import java.util.Comparator;
|
||||||
@@ -43,19 +40,18 @@ public class SteadyDataViewTrendServiceImpl implements SteadyDataViewTrendServic
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
public SteadyTrendQueryVO queryTrend(SteadyTrendQueryParam param) {
|
public SteadyTrendQueryVO queryTrend(SteadyTrendQueryParam param) {
|
||||||
return queryTrendInternal(param, true);
|
return queryTrendInternal(param);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public SteadyTrendQueryVO queryTrendDay(SteadyTrendQueryParam param) {
|
public SteadyTrendQueryVO queryTrendDay(SteadyTrendQueryParam param) {
|
||||||
return queryTrendInternal(param, true);
|
return queryTrendInternal(param);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public SteadyTrendSummaryVO summarizeTrend(SteadyTrendQueryParam param) {
|
public SteadyTrendSummaryVO summarizeTrend(SteadyTrendQueryParam param) {
|
||||||
SteadyTrendQueryParam summaryParam = copyParam(param);
|
SteadyTrendQueryParam summaryParam = copyParam(param);
|
||||||
summaryParam.setBucket(null);
|
SteadyTrendQueryVO trend = queryTrendInternal(summaryParam);
|
||||||
SteadyTrendQueryVO trend = queryTrendInternal(summaryParam, false);
|
|
||||||
SteadyTrendSummaryVO result = new SteadyTrendSummaryVO();
|
SteadyTrendSummaryVO result = new SteadyTrendSummaryVO();
|
||||||
for (SteadyTrendSeriesVO series : trend.getSeries()) {
|
for (SteadyTrendSeriesVO series : trend.getSeries()) {
|
||||||
result.getItems().add(buildSummaryItem(series));
|
result.getItems().add(buildSummaryItem(series));
|
||||||
@@ -63,20 +59,18 @@ public class SteadyDataViewTrendServiceImpl implements SteadyDataViewTrendServic
|
|||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
private SteadyTrendQueryVO queryTrendInternal(SteadyTrendQueryParam param, boolean autoBucket) {
|
private SteadyTrendQueryVO queryTrendInternal(SteadyTrendQueryParam param) {
|
||||||
LocalDateTime startTime = fieldResolver.parseRequiredTime(param == null ? null : param.getTimeStart(), "开始时间不能为空");
|
LocalDateTime startTime = fieldResolver.parseRequiredTime(param == null ? null : param.getTimeStart(), "开始时间不能为空");
|
||||||
LocalDateTime endTime = fieldResolver.parseRequiredTime(param == null ? null : param.getTimeEnd(), "结束时间不能为空");
|
LocalDateTime endTime = fieldResolver.parseRequiredTime(param == null ? null : param.getTimeEnd(), "结束时间不能为空");
|
||||||
List<SteadyTrendResolvedFieldBO> fields = fieldResolver.resolveFields(param);
|
List<SteadyTrendResolvedFieldBO> fields = fieldResolver.resolveFields(param);
|
||||||
enrichLineNames(fields);
|
enrichLineNames(fields);
|
||||||
String bucket = autoBucket ? resolveBucket(param.getBucket(), startTime, endTime) : null;
|
|
||||||
|
|
||||||
SteadyTrendQueryVO result = new SteadyTrendQueryVO();
|
SteadyTrendQueryVO result = new SteadyTrendQueryVO();
|
||||||
result.setBucket(bucket);
|
result.setSampled(false);
|
||||||
result.setSampled(bucket != null);
|
|
||||||
result.setLoadableDays(resolveLoadableDays(startTime, endTime));
|
result.setLoadableDays(resolveLoadableDays(startTime, endTime));
|
||||||
int displayPointCount = 0;
|
int displayPointCount = 0;
|
||||||
for (SteadyTrendResolvedFieldBO field : fields) {
|
for (SteadyTrendResolvedFieldBO field : fields) {
|
||||||
List<SteadyTrendPointVO> points = influxQueryComponent.queryTrendPoints(field, startTime, endTime, bucket, param.getQualityFlag());
|
List<SteadyTrendPointVO> points = influxQueryComponent.queryTrendPoints(field, startTime, endTime, param.getQualityFlag());
|
||||||
displayPointCount += points.size();
|
displayPointCount += points.size();
|
||||||
result.getSeries().add(buildSeries(field, points));
|
result.getSeries().add(buildSeries(field, points));
|
||||||
}
|
}
|
||||||
@@ -143,27 +137,6 @@ public class SteadyDataViewTrendServiceImpl implements SteadyDataViewTrendServic
|
|||||||
return item;
|
return item;
|
||||||
}
|
}
|
||||||
|
|
||||||
private String resolveBucket(String requestBucket, LocalDateTime startTime, LocalDateTime endTime) {
|
|
||||||
String bucket = trimToNull(requestBucket);
|
|
||||||
if (bucket != null) {
|
|
||||||
if (!bucket.matches("^[1-9][0-9]*(m|h|d)$")) {
|
|
||||||
throw fail("分桶粒度仅支持 m、h、d,例如 10m、1h");
|
|
||||||
}
|
|
||||||
return bucket;
|
|
||||||
}
|
|
||||||
long hours = ChronoUnit.HOURS.between(startTime, endTime);
|
|
||||||
if (hours < 6) {
|
|
||||||
return "1m";
|
|
||||||
}
|
|
||||||
if (hours <= 24) {
|
|
||||||
return "10m";
|
|
||||||
}
|
|
||||||
if (hours <= 24 * 7) {
|
|
||||||
return "30m";
|
|
||||||
}
|
|
||||||
return "1h";
|
|
||||||
}
|
|
||||||
|
|
||||||
private List<String> resolveLoadableDays(LocalDateTime startTime, LocalDateTime endTime) {
|
private List<String> resolveLoadableDays(LocalDateTime startTime, LocalDateTime endTime) {
|
||||||
List<String> result = new ArrayList<String>();
|
List<String> result = new ArrayList<String>();
|
||||||
LocalDate date = startTime.toLocalDate();
|
LocalDate date = startTime.toLocalDate();
|
||||||
@@ -185,7 +158,6 @@ public class SteadyDataViewTrendServiceImpl implements SteadyDataViewTrendServic
|
|||||||
target.setStatTypes(copyList(source.getStatTypes()));
|
target.setStatTypes(copyList(source.getStatTypes()));
|
||||||
target.setTimeStart(source.getTimeStart());
|
target.setTimeStart(source.getTimeStart());
|
||||||
target.setTimeEnd(source.getTimeEnd());
|
target.setTimeEnd(source.getTimeEnd());
|
||||||
target.setBucket(source.getBucket());
|
|
||||||
target.setQualityFlag(source.getQualityFlag());
|
target.setQualityFlag(source.getQualityFlag());
|
||||||
target.setHarmonicOrders(source.getHarmonicOrders() == null ? Collections.<Integer>emptyList() : new ArrayList<Integer>(source.getHarmonicOrders()));
|
target.setHarmonicOrders(source.getHarmonicOrders() == null ? Collections.<Integer>emptyList() : new ArrayList<Integer>(source.getHarmonicOrders()));
|
||||||
return target;
|
return target;
|
||||||
@@ -203,7 +175,4 @@ public class SteadyDataViewTrendServiceImpl implements SteadyDataViewTrendServic
|
|||||||
return trimmed.isEmpty() ? null : trimmed;
|
return trimmed.isEmpty() ? null : trimmed;
|
||||||
}
|
}
|
||||||
|
|
||||||
private BusinessException fail(String message) {
|
|
||||||
return new BusinessException(CommonResponseEnum.FAIL, message);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -0,0 +1,94 @@
|
|||||||
|
package com.njcn.gather.steady.datavie.component;
|
||||||
|
|
||||||
|
import com.njcn.gather.steady.datavie.config.SteadyInfluxDbProperties;
|
||||||
|
import com.njcn.gather.steady.datavie.pojo.bo.SteadyTrendResolvedFieldBO;
|
||||||
|
import org.junit.jupiter.api.Assertions;
|
||||||
|
import org.junit.jupiter.api.Test;
|
||||||
|
|
||||||
|
import java.time.LocalDateTime;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 稳态趋势 InfluxQL 构造契约测试。
|
||||||
|
*/
|
||||||
|
class SteadyInfluxQueryComponentTest {
|
||||||
|
|
||||||
|
@Test
|
||||||
|
void shouldBuildRawPointQueryWithoutTimeBucketAggregation() {
|
||||||
|
SteadyInfluxQueryComponent component = new SteadyInfluxQueryComponent(new SteadyInfluxDbProperties());
|
||||||
|
SteadyTrendResolvedFieldBO field = new SteadyTrendResolvedFieldBO();
|
||||||
|
field.setMeasurement("data_v");
|
||||||
|
field.setField("RMS");
|
||||||
|
field.setLineId("line-001");
|
||||||
|
field.setPhase("A");
|
||||||
|
|
||||||
|
String query = component.buildTrendQuery(field,
|
||||||
|
LocalDateTime.of(2026, 5, 1, 0, 0, 0),
|
||||||
|
LocalDateTime.of(2026, 5, 1, 23, 59, 59),
|
||||||
|
1);
|
||||||
|
|
||||||
|
Assertions.assertTrue(query.startsWith("SELECT \"RMS\" AS \"value\""), "趋势查询应读取原始字段值");
|
||||||
|
Assertions.assertTrue(query.endsWith(" ORDER BY time ASC"), "趋势查询应按原始时间升序返回");
|
||||||
|
Assertions.assertFalse(query.contains("mean("), "趋势查询不应按颗粒度聚合");
|
||||||
|
Assertions.assertFalse(query.contains("GROUP BY time"), "趋势查询不应生成时间分桶");
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
void shouldBuildQueryWithActualInfluxTagsAndValueType() {
|
||||||
|
SteadyInfluxQueryComponent component = new SteadyInfluxQueryComponent(new SteadyInfluxDbProperties());
|
||||||
|
SteadyTrendResolvedFieldBO field = new SteadyTrendResolvedFieldBO();
|
||||||
|
field.setMeasurement("data_v");
|
||||||
|
field.setField("rms");
|
||||||
|
field.setLineId("00B78D00A8791");
|
||||||
|
field.setPhase("A");
|
||||||
|
field.setStatType("AVG");
|
||||||
|
|
||||||
|
String query = component.buildTrendQuery(field,
|
||||||
|
LocalDateTime.of(2026, 5, 1, 0, 0, 0),
|
||||||
|
LocalDateTime.of(2026, 5, 1, 23, 59, 59),
|
||||||
|
0);
|
||||||
|
|
||||||
|
Assertions.assertTrue(query.contains("\"line_id\" = '00B78D00A8791'"));
|
||||||
|
Assertions.assertTrue(query.contains("\"phasic_type\" = 'A'"));
|
||||||
|
Assertions.assertTrue(query.contains("\"quality_flag\" = '0'"));
|
||||||
|
Assertions.assertTrue(query.contains("\"value_type\" = 'AVG'"));
|
||||||
|
Assertions.assertFalse(query.contains("\"LINEID\""));
|
||||||
|
Assertions.assertFalse(query.contains("\"PHASIC_TYPE\""));
|
||||||
|
Assertions.assertFalse(query.contains("\"QUALITYFLAG\""));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
void shouldDefaultValueTypeToUpperAvg() {
|
||||||
|
SteadyInfluxQueryComponent component = new SteadyInfluxQueryComponent(new SteadyInfluxDbProperties());
|
||||||
|
SteadyTrendResolvedFieldBO field = new SteadyTrendResolvedFieldBO();
|
||||||
|
field.setMeasurement("data_v");
|
||||||
|
field.setField("rms");
|
||||||
|
field.setLineId("0798e5a9a72ebbc4daaa4a631701c813");
|
||||||
|
field.setPhase("A");
|
||||||
|
|
||||||
|
String query = component.buildTrendQuery(field,
|
||||||
|
LocalDateTime.of(2026, 5, 1, 0, 0, 0),
|
||||||
|
LocalDateTime.of(2026, 5, 1, 23, 59, 59),
|
||||||
|
0);
|
||||||
|
|
||||||
|
Assertions.assertTrue(query.contains("\"value_type\" = 'AVG'"));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
void shouldSkipValueTypeWhenMeasurementHasNoValueTypeTag() {
|
||||||
|
SteadyInfluxQueryComponent component = new SteadyInfluxQueryComponent(new SteadyInfluxDbProperties());
|
||||||
|
SteadyTrendResolvedFieldBO field = new SteadyTrendResolvedFieldBO();
|
||||||
|
field.setMeasurement("data_fluc");
|
||||||
|
field.setField("fluc");
|
||||||
|
field.setLineId("0798e5a9a72ebbc4daaa4a631701c813");
|
||||||
|
field.setPhase("T");
|
||||||
|
field.setStatType("AVG");
|
||||||
|
|
||||||
|
String query = component.buildTrendQuery(field,
|
||||||
|
LocalDateTime.of(2026, 5, 1, 0, 0, 0),
|
||||||
|
LocalDateTime.of(2026, 5, 1, 23, 59, 59),
|
||||||
|
0);
|
||||||
|
|
||||||
|
Assertions.assertFalse(query.contains("\"value_type\""));
|
||||||
|
Assertions.assertTrue(query.contains("\"quality_flag\" = '0'"));
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -3,7 +3,6 @@ package com.njcn.gather.steady.datavie.component;
|
|||||||
import com.njcn.common.pojo.exception.BusinessException;
|
import com.njcn.common.pojo.exception.BusinessException;
|
||||||
import com.njcn.gather.steady.datavie.pojo.bo.SteadyTrendResolvedFieldBO;
|
import com.njcn.gather.steady.datavie.pojo.bo.SteadyTrendResolvedFieldBO;
|
||||||
import com.njcn.gather.steady.datavie.pojo.param.SteadyTrendQueryParam;
|
import com.njcn.gather.steady.datavie.pojo.param.SteadyTrendQueryParam;
|
||||||
import com.njcn.gather.tool.adddata.component.AddDataTableRegistry;
|
|
||||||
import org.junit.jupiter.api.Assertions;
|
import org.junit.jupiter.api.Assertions;
|
||||||
import org.junit.jupiter.api.BeforeEach;
|
import org.junit.jupiter.api.BeforeEach;
|
||||||
import org.junit.jupiter.api.Test;
|
import org.junit.jupiter.api.Test;
|
||||||
@@ -20,10 +19,8 @@ class SteadyTrendFieldResolverTest {
|
|||||||
private SteadyTrendFieldResolver resolver;
|
private SteadyTrendFieldResolver resolver;
|
||||||
|
|
||||||
@BeforeEach
|
@BeforeEach
|
||||||
void setUp() throws Exception {
|
void setUp() {
|
||||||
AddDataTableRegistry tableRegistry = new AddDataTableRegistry();
|
resolver = new SteadyTrendFieldResolver(new SteadyTrendIndicatorCatalog());
|
||||||
tableRegistry.afterPropertiesSet();
|
|
||||||
resolver = new SteadyTrendFieldResolver(new SteadyTrendIndicatorCatalog(), tableRegistry);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
@@ -41,6 +38,21 @@ class SteadyTrendFieldResolverTest {
|
|||||||
Assertions.assertEquals(Arrays.asList("A", "B", "C"), phases);
|
Assertions.assertEquals(Arrays.asList("A", "B", "C"), phases);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
void shouldResolveVoltageRmsToActualInfluxField() {
|
||||||
|
SteadyTrendQueryParam param = new SteadyTrendQueryParam();
|
||||||
|
param.setLineIds(Arrays.asList("00B78D00A8791"));
|
||||||
|
param.setIndicatorCodes(Arrays.asList("V_RMS"));
|
||||||
|
param.setStatTypes(Arrays.asList("AVG"));
|
||||||
|
param.setTimeStart("2026-05-01 00:00:00");
|
||||||
|
param.setTimeEnd("2026-05-01 01:00:00");
|
||||||
|
|
||||||
|
List<SteadyTrendResolvedFieldBO> fields = resolver.resolveFields(param);
|
||||||
|
|
||||||
|
Assertions.assertEquals("rms", fields.get(0).getField());
|
||||||
|
Assertions.assertEquals("00B78D00A8791|V_RMS|A|AVG|rms", fields.get(0).getSeriesKey());
|
||||||
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
void shouldExpandTotalPhaseIndicatorWithoutRequestPhaseFilter() {
|
void shouldExpandTotalPhaseIndicatorWithoutRequestPhaseFilter() {
|
||||||
SteadyTrendQueryParam param = new SteadyTrendQueryParam();
|
SteadyTrendQueryParam param = new SteadyTrendQueryParam();
|
||||||
@@ -52,11 +64,35 @@ class SteadyTrendFieldResolverTest {
|
|||||||
|
|
||||||
List<SteadyTrendResolvedFieldBO> fields = resolver.resolveFields(param);
|
List<SteadyTrendResolvedFieldBO> fields = resolver.resolveFields(param);
|
||||||
|
|
||||||
Assertions.assertEquals(3, fields.size());
|
Assertions.assertEquals(1, fields.size());
|
||||||
Assertions.assertEquals("T", fields.get(0).getPhase());
|
Assertions.assertEquals("T", fields.get(0).getPhase());
|
||||||
Assertions.assertEquals("RMSAB", fields.get(0).getField());
|
Assertions.assertEquals("rms_lvr", fields.get(0).getField());
|
||||||
Assertions.assertEquals("RMSBC", fields.get(1).getField());
|
}
|
||||||
Assertions.assertEquals("RMSCA", fields.get(2).getField());
|
|
||||||
|
@Test
|
||||||
|
void shouldResolveCommonIndicatorsToActualInfluxFields() {
|
||||||
|
Assertions.assertEquals("freq", resolveSingleField("FREQ"));
|
||||||
|
Assertions.assertEquals("v_thd", resolveSingleField("V_THD"));
|
||||||
|
Assertions.assertEquals("rms", resolveSingleField("I_RMS"));
|
||||||
|
Assertions.assertEquals("i_thd", resolveSingleField("I_THD"));
|
||||||
|
Assertions.assertEquals("fluc", resolveSingleField("FLUC"));
|
||||||
|
Assertions.assertEquals("pst", resolveSingleField("PST"));
|
||||||
|
Assertions.assertEquals("plt", resolveSingleField("PLT"));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
void shouldExposeActualInfluxFieldsInIndicatorCatalog() {
|
||||||
|
SteadyTrendIndicatorCatalog catalog = new SteadyTrendIndicatorCatalog();
|
||||||
|
|
||||||
|
Assertions.assertEquals("rms", catalog.getIndicator("V_RMS").getSeriesFields().get(0).getField());
|
||||||
|
Assertions.assertEquals("rms_lvr", catalog.getIndicator("V_LINE_RMS").getSeriesFields().get(0).getField());
|
||||||
|
Assertions.assertEquals("freq", catalog.getIndicator("FREQ").getSeriesFields().get(0).getField());
|
||||||
|
Assertions.assertEquals("v_thd", catalog.getIndicator("V_THD").getSeriesFields().get(0).getField());
|
||||||
|
Assertions.assertEquals("rms", catalog.getIndicator("I_RMS").getSeriesFields().get(0).getField());
|
||||||
|
Assertions.assertEquals("i_thd", catalog.getIndicator("I_THD").getSeriesFields().get(0).getField());
|
||||||
|
Assertions.assertEquals("fluc", catalog.getIndicator("FLUC").getSeriesFields().get(0).getField());
|
||||||
|
Assertions.assertEquals("pst", catalog.getIndicator("PST").getSeriesFields().get(0).getField());
|
||||||
|
Assertions.assertEquals("plt", catalog.getIndicator("PLT").getSeriesFields().get(0).getField());
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
@@ -87,9 +123,34 @@ class SteadyTrendFieldResolverTest {
|
|||||||
|
|
||||||
Assertions.assertEquals(6, fields.size());
|
Assertions.assertEquals(6, fields.size());
|
||||||
Assertions.assertEquals("A", fields.get(0).getPhase());
|
Assertions.assertEquals("A", fields.get(0).getPhase());
|
||||||
Assertions.assertEquals("V_3_MAX", fields.get(0).getField());
|
Assertions.assertEquals("v_3", fields.get(0).getField());
|
||||||
Assertions.assertEquals("V_5_MAX", fields.get(1).getField());
|
Assertions.assertEquals("v_5", fields.get(1).getField());
|
||||||
Assertions.assertEquals("B", fields.get(2).getPhase());
|
Assertions.assertEquals("B", fields.get(2).getPhase());
|
||||||
Assertions.assertEquals("C", fields.get(4).getPhase());
|
Assertions.assertEquals("C", fields.get(4).getPhase());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
void shouldResolveHarmonicPowerToActualInfluxField() {
|
||||||
|
SteadyTrendQueryParam param = new SteadyTrendQueryParam();
|
||||||
|
param.setLineIds(Arrays.asList("line-001"));
|
||||||
|
param.setIndicatorCodes(Arrays.asList("P_HARMONIC_POWER"));
|
||||||
|
param.setStatTypes(Arrays.asList("CP95"));
|
||||||
|
param.setHarmonicOrders(Arrays.asList(3));
|
||||||
|
param.setTimeStart("2026-05-01 00:00:00");
|
||||||
|
param.setTimeEnd("2026-05-01 01:00:00");
|
||||||
|
|
||||||
|
List<SteadyTrendResolvedFieldBO> fields = resolver.resolveFields(param);
|
||||||
|
|
||||||
|
Assertions.assertEquals("p_3", fields.get(0).getField());
|
||||||
|
}
|
||||||
|
|
||||||
|
private String resolveSingleField(String indicatorCode) {
|
||||||
|
SteadyTrendQueryParam param = new SteadyTrendQueryParam();
|
||||||
|
param.setLineIds(Arrays.asList("line-001"));
|
||||||
|
param.setIndicatorCodes(Arrays.asList(indicatorCode));
|
||||||
|
param.setStatTypes(Arrays.asList("AVG"));
|
||||||
|
param.setTimeStart("2026-05-01 00:00:00");
|
||||||
|
param.setTimeEnd("2026-05-01 01:00:00");
|
||||||
|
return resolver.resolveFields(param).get(0).getField();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -16,4 +16,5 @@ class SteadyTrendQueryParamTest {
|
|||||||
Assertions.assertNotEquals("phases", field.getName(), "趋势检索请求不再携带相别条件");
|
Assertions.assertNotEquals("phases", field.getName(), "趋势检索请求不再携带相别条件");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user