package com.ruoyi.system.service.impl;
|
|
import java.math.BigDecimal;
|
import java.util.Date;
|
import com.alibaba.fastjson2.JSON;
|
import org.springframework.stereotype.Service;
|
import org.springframework.transaction.annotation.Transactional;
|
import com.ruoyi.system.domain.TTest;
|
import com.ruoyi.system.domain.TTestWarningException;
|
import com.ruoyi.system.domain.TTestWarningThreshold;
|
import com.ruoyi.system.mapper.TTestMapper;
|
|
/** 对成功接收的测量值执行测试阈值判断;设备状态和缺失数据不经过此服务。 */
|
@Service
|
public class TestWarningExceptionService {
|
private final TTestMapper mapper;
|
public TestWarningExceptionService(TTestMapper mapper) { this.mapper = mapper; }
|
/** 仅对成功接收的非空测量值判定阈值,并聚合更新开放异常及规则快照。 */
|
public void evaluate(TTest test, String sourceType, String sourceIdentity, String metricCode, BigDecimal value, String unit, Date occurredAt) {
|
if (value == null || test == null || test.getThresholds() == null) return;
|
for (TTestWarningThreshold rule : test.getThresholds()) {
|
if (rule == null || rule.getMetricCode() == null || !matches(rule.getMetricCode(), metricCode)
|
|| !outside(value, rule.getMinValue(), rule.getMaxValue())) continue;
|
mapper.upsertWarningException(test.getTestId(), rule.getThresholdId(), sourceType, sourceIdentity, metricCode, value, unit,
|
JSON.toJSONString(rule), rule.getSeverity(), occurredAt == null ? new Date() : occurredAt);
|
}
|
}
|
|
/** 由测试负责人关闭开放异常,并在同一事务追加不可变的测试审计事实。 */
|
@Transactional(rollbackFor = Exception.class)
|
public int close(Long exceptionId, Long actorId, String actorName, String handlingNote) {
|
TTestWarningException exception = mapper.selectWarningExceptionById(exceptionId);
|
if (exception == null) return 0;
|
int rows = mapper.closeWarningException(exceptionId, actorId, actorName, new Date(), handlingNote);
|
if (rows == 1) {
|
mapper.insertTestAudit(exception.getTestId(), "WARNING_EXCEPTION_CLOSED", actorId, actorName, null,
|
JSON.toJSONString(java.util.Map.of("exceptionId", exceptionId, "handlingNote", handlingNote)));
|
}
|
return rows;
|
}
|
private boolean outside(BigDecimal value, BigDecimal min, BigDecimal max) { return (min != null && value.compareTo(min) < 0) || (max != null && value.compareTo(max) > 0); }
|
private boolean matches(String configured, String actual) {
|
if (actual == null) return false;
|
if (configured.equalsIgnoreCase(actual)) return true;
|
String c = configured.toUpperCase(), a = actual.toUpperCase();
|
return (c.contains("VOLTAGE") && a.contains("VOLTAGE")) || (c.contains("CURRENT") && a.contains("CURRENT"))
|
|| (c.contains("CAPACITY") && a.contains("CAPACITY")) || (c.contains("ENERGY") && a.contains("ENERGY"))
|
|| (c.contains("TEMPERATURE") && a.contains("TEMPERATURE")) || (c.contains("POSITIVE_POTENTIAL") && a.contains("POSITIVE_POTENTIAL"))
|
|| (c.contains("NEGATIVE_POTENTIAL") && a.contains("NEGATIVE_POTENTIAL"));
|
}
|
}
|