package jnpf.task;
import jnpf.entity.EquipmentparameterEntity;
import jnpf.entity.UleabnormalrecordsEntity;
import jnpf.myutils.DateUtils;
import jnpf.service.*;
import lombok.extern.slf4j.Slf4j;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import java.text.DateFormat;
import java.text.SimpleDateFormat;
import java.time.*;
import java.time.format.DateTimeFormatter;
import java.util.*;
import java.util.stream.Collectors;
@Slf4j
@Component
public class HAHFAnalysisTask {
private static final Logger logger = LoggerFactory.getLogger(HAHFAnalysisTask.class);
private static final int BUCKET_SIZE = 6; // 6小时分桶
private static final int MIN_DATA_POINTS = 4; // 最小数据点数
private static final int HOURS_IN_DAY = 24; // 一天的小时数
private static final int RECOVERY_WINDOW_HOURS = 24; // 恢复判断窗口小时数
@Autowired
private EquipmentparameterService equipmentparameterService;
@Autowired
private UleabnormalrecordsService uleabnormalrecordsService;
@Autowired
private RealDataService realDataService;
@Autowired
private EquipmentledgerService equipmentledgerService;
@Autowired
private ProcessmanageService processmanageService;
DateFormat df = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
//@XxlJob("hahfAnalysis")
public void hahfAnalysis() {
logger.info("HAHF分析任务启动");
// 1. 获取TSP设备列表
List<EquipmentparameterEntity> equipmentList = equipmentparameterService.geHAHFList();
if (equipmentList.isEmpty()) {
logger.info("没有可分析的TSP设备");
return;
}
// 2. 准备查询参数
Map<String, Object> params = new HashMap<>();
List<String> tags = equipmentList.stream()
.map(EquipmentparameterEntity::getTag)
.collect(Collectors.toList());
params.put("tags", tags);
// 3. 获取日常值数据
params.put("begindate", DateUtils.dataTimeformat(new Date()));
List<Map> dailyValue = realDataService.selectLastmonthDailyvalue(params);
Map<String, Map<String, Object>> dailyValueMap = dailyValue.stream()
.collect(Collectors.toMap(
m -> (String) m.get("datag"),
m -> m
));
// 4. 获取小时数据(从前一天开始时间到当前时间)
LocalDateTime endTime = LocalDateTime.now();
// 获取前一天开始时间(00:00:00)
LocalDateTime startTime = LocalDate.now().minusDays(1).atStartOfDay();
params.put("begindate", formatDateTime(startTime));
params.put("enddate", formatDateTime(endTime));
List<Map> hourDataMaps = realDataService.selectHourdataByTagIdsAndDate(params);
// 5. 按tag分组小时数据
Map<String, List<Map>> hourDataByTag = hourDataMaps.stream()
.collect(Collectors.groupingBy(
m -> (String) m.get("datag")
));
// 6. 获取当前报警中的记录
List<UleabnormalrecordsEntity> activeAlarms = uleabnormalrecordsService.getOnhahfList();
Map<String, UleabnormalrecordsEntity> activeAlarmMap = activeAlarms.stream()
.collect(Collectors.toMap(
UleabnormalrecordsEntity::getParacode,
alarm -> alarm
));
// 7. 处理每个设备
for (EquipmentparameterEntity equipment : equipmentList) {
try {
processEquipment(
equipment,
dailyValueMap,
hourDataByTag,
activeAlarmMap,
startTime,
endTime
);
} catch (Exception e) {
logger.error("处理设备{}失败: {}", equipment.getEncode(), e.getMessage(), e);
}
}
logger.info("HAHF分析任务完成,共处理{}个设备", equipmentList.size());
}
private void processEquipment(EquipmentparameterEntity equipment,
Map<String, Map<String, Object>> dailyValueMap,
Map<String, List<Map>> hourDataByTag,
Map<String, UleabnormalrecordsEntity> activeAlarmMap,
LocalDateTime analysisStart,
LocalDateTime analysisEnd) {
String tag = equipment.getTag();
String paraCode = equipment.getEncode();
// 获取该tag的日常值配置
Map<String, Object> dailyConfig = dailyValueMap.get(tag);
if (dailyConfig == null) {
logger.warn("设备{}缺少日常值", paraCode);
return;
}
double farBeyondValue = ((Number) dailyConfig.get("farbeyondvalue")).doubleValue();
double limitingValue = ((Number) dailyConfig.get("limitingvalue")).doubleValue();
// 获取该tag的小时数据
List<Map> hourDataList = hourDataByTag.getOrDefault(tag, new ArrayList<>());
// 无小时数据直接返回
if (hourDataList.isEmpty()) {
logger.info("设备{}没有小时数据", paraCode);
return;
}
// 准备时间序列数据
List<DataPoint> dataPoints = prepareDataPoints(hourDataList);
// 按时间排序
dataPoints.sort(Comparator.comparing(DataPoint::getDateTime));
// 获取最后数据点的时间和值
DataPoint lastDataPoint = dataPoints.get(dataPoints.size() - 1);
LocalDateTime lastDataTime = lastDataPoint.dateTime;
double lastDataValue = lastDataPoint.value;
// 添加调试信息
logger.debug("设备{}有{}个数据点,时间范围: {} 到 {},最后数据点: {}={}",
paraCode, dataPoints.size(),
dataPoints.get(0).dateTime,
dataPoints.get(dataPoints.size()-1).dateTime,
lastDataTime, lastDataValue);
// 设备有报警中记录 - 无论阈值条件是否满足,都需要检查恢复
if (activeAlarmMap.containsKey(paraCode)) {
handleActiveAlarm(
activeAlarmMap.get(paraCode),
dataPoints,
farBeyondValue,
limitingValue,
analysisEnd,
lastDataTime,
lastDataValue
);
}
// 设备无报警中记录 - 只有满足阈值条件时才处理
else {
// 检查是否满足报警条件
boolean isValidForAlarm = isValidForAlarm(dataPoints, farBeyondValue, limitingValue);
if (isValidForAlarm) {
handleNewAlarm(
equipment,
dataPoints,
farBeyondValue,
limitingValue,
analysisEnd,
lastDataTime,
lastDataValue
);
} else {
logger.info("设备{}数据不满足报警条件", paraCode);
}
}
}
// ===================== 报警处理核心逻辑 =====================
/**
* 处理新报警检测
*/
private void handleNewAlarm(EquipmentparameterEntity equipment,
List<DataPoint> dataPoints,
double farBeyondValue,
double limitingValue,
LocalDateTime analysisEnd,
LocalDateTime lastDataTime,
double lastDataValue) {
// 寻找所有符合条件的连续时间段
List<TimePeriod> validPeriods = findValidPeriods(dataPoints, farBeyondValue, limitingValue, lastDataTime, analysisEnd);
if (validPeriods.isEmpty()) {
logger.info("设备{}满足阈值条件但未找到有效时间段", equipment.getEncode());
return;
}
// 合并连续的时间段
List<TimePeriod> mergedPeriods = mergeContinuousPeriods(validPeriods);
// 创建报警记录
for (TimePeriod period : mergedPeriods) {
// 确定实际报警开始和结束时间
LocalDateTime actualStart = findActualStartTime(dataPoints, period.start, farBeyondValue, limitingValue);
LocalDateTime actualEnd = findActualEndTime(dataPoints, period.end, farBeyondValue, limitingValue, analysisEnd);
createAlarmRecord(equipment, actualStart, actualEnd);
}
}
/**
* 处理活跃报警
*/
private void handleActiveAlarm(UleabnormalrecordsEntity activeAlarm,
List<DataPoint> dataPoints,
double farBeyondValue,
double limitingValue,
LocalDateTime analysisEnd,
LocalDateTime lastDataTime,
double lastDataValue) {
LocalDateTime alarmStartTime = toLocalDateTime(activeAlarm.getAbnormaltime());
// 检查报警是否恢复:连续24小时不满足条件才算恢复
LocalDateTime recoveryTime = checkRecovery(
dataPoints,
alarmStartTime,
farBeyondValue,
limitingValue,
analysisEnd
);
// 情况1: 报警恢复
if (recoveryTime != null) {
completeAlarm(activeAlarm, recoveryTime);
// 检查恢复后是否再次触发报警
List<DataPoint> postRecoveryData = dataPoints.stream()
.filter(point -> point.dateTime.isAfter(recoveryTime))
.collect(Collectors.toList());
if (!postRecoveryData.isEmpty()) {
DataPoint lastPostDataPoint = postRecoveryData.get(postRecoveryData.size() - 1);
if (isValidForAlarm(postRecoveryData, farBeyondValue, limitingValue)) {
EquipmentparameterEntity equipment = new EquipmentparameterEntity();
equipment.setEncode(activeAlarm.getParacode());
equipment.setTag(activeAlarm.getParacode());
equipment.setEquipmentledgerid(activeAlarm.getEquipmentid());
equipment.setFullname(activeAlarm.getParaname());
handleNewAlarm(
equipment,
postRecoveryData,
farBeyondValue,
limitingValue,
analysisEnd,
lastPostDataPoint.dateTime,
lastPostDataPoint.value
);
}
}
}
// 情况2: 报警持续中
else {
// 检查最后一个数据点是否仍超过阈值,确保报警状态正确
if (lastDataValue >= limitingValue) {
logger.info("报警{}仍在持续中,已持续{}小时",
activeAlarm.getId(),
Duration.between(alarmStartTime, LocalDateTime.now()).toHours());
} else {
// 最后一个点低于阈值但未满足恢复条件,可能是短暂波动
logger.info("报警{}最后数据点低于阈值但未确认恢复,继续观察", activeAlarm.getId());
}
}
}
// ===================== 报警检测算法 =====================
/**
* 核心算法:寻找有效时间段
*/
private List<TimePeriod> findValidPeriods(List<DataPoint> dataPoints,
double farBeyondValue,
double limitingValue,
LocalDateTime lastDataTime,
LocalDateTime analysisEnd) {
List<TimePeriod> validPeriods = new ArrayList<>();
if (dataPoints.size() < MIN_DATA_POINTS) {
return validPeriods;
}
// 按日期和时间排序
dataPoints.sort(Comparator.comparing(DataPoint::getDateTime));
// 使用滑动窗口检测24小时时间段
int i = 0;
while (i < dataPoints.size()) {
LocalDateTime windowStart = dataPoints.get(i).dateTime;
LocalDateTime windowEnd = windowStart.plusHours(HOURS_IN_DAY);
// 获取窗口内的数据点
List<DataPoint> windowData = new ArrayList<>();
int j = i;
while (j < dataPoints.size()) {
DataPoint point = dataPoints.get(j);
if (point.dateTime.isBefore(windowEnd)) {
windowData.add(point);
j++;
} else {
break;
}
}
// 检查窗口有效性
if (isValidPeriod(windowData, farBeyondValue, limitingValue, windowStart, windowEnd)) {
// 确定时间段结束时间
LocalDateTime periodEnd;
// 如果窗口结束时间在最后数据时间之后,且最后数据仍超过阈值,则结束时间为null(持续中)
if (windowEnd.isAfter(lastDataTime) && lastDataTime.isAfter(windowStart) &&
dataPoints.get(dataPoints.size() - 1).value >= limitingValue) {
periodEnd = null;
} else {
periodEnd = windowEnd;
}
validPeriods.add(new TimePeriod(windowStart, periodEnd));
// 移动到窗口结束位置,避免重复检测
i = j;
} else {
i++;
}
}
return validPeriods;
}
/**
* 检查24小时窗口是否有效
*/
private boolean isValidPeriod(List<DataPoint> dataPoints,
double farBeyondValue,
double limitingValue,
LocalDateTime windowStart,
LocalDateTime windowEnd) {
if (dataPoints.isEmpty()) {
return false;
}
// 检查时间跨度是否足够(至少24小时)
Duration duration = Duration.between(windowStart, windowEnd);
if (duration.toHours() < HOURS_IN_DAY) {
return false;
}
// 检查限制值条件 - 窗口内所有数据点都要大于等于limitingValue
boolean allAboveLimiting = dataPoints.stream()
.allMatch(point -> point.value >= limitingValue);
if (!allAboveLimiting) {
return false;
}
// 按6小时分桶组织数据
Map<Integer, List<DataPoint>> bucketMap = new HashMap<>();
for (DataPoint point : dataPoints) {
int bucketIdx = point.dateTime.getHour() / BUCKET_SIZE;
bucketMap.computeIfAbsent(bucketIdx, k -> new ArrayList<>()).add(point);
}
// 检查每个桶是否满足条件:每个6小时桶至少有一个点远高于日常值
for (int bucketIdx = 0; bucketIdx < 4; bucketIdx++) {
List<DataPoint> bucketData = bucketMap.getOrDefault(bucketIdx, new ArrayList<>());
// 桶内无数据或没有有效点
if (bucketData.isEmpty() ||
bucketData.stream().noneMatch(point -> point.value >= farBeyondValue)) {
return false;
}
}
return true;
}
/**
* 检查报警恢复:需要连续24小时不满足报警条件
*/
private LocalDateTime checkRecovery(List<DataPoint> dataPoints,
LocalDateTime startTime,
double farBeyondValue,
double limitingValue,
LocalDateTime analysisEnd) {
if (dataPoints.isEmpty()) {
return null;
}
// 过滤出报警开始时间之后的数据
List<DataPoint> postAlarmData = dataPoints.stream()
.filter(point -> !point.dateTime.isBefore(startTime))
.collect(Collectors.toList());
if (postAlarmData.isEmpty()) {
return null;
}
// 检查是否有连续24小时不满足条件
for (int i = 0; i < postAlarmData.size(); i++) {
LocalDateTime windowStart = postAlarmData.get(i).dateTime;
LocalDateTime windowEnd = windowStart.plusHours(RECOVERY_WINDOW_HOURS);
// 如果窗口超出分析结束时间,则调整窗口结束时间
if (windowEnd.isAfter(analysisEnd)) {
windowEnd = analysisEnd;
}
// 获取窗口内的数据点
List<DataPoint> windowData = new ArrayList<>();
for (int j = i; j < postAlarmData.size(); j++) {
DataPoint point = postAlarmData.get(j);
if (point.dateTime.isBefore(windowEnd)) {
windowData.add(point);
} else {
break;
}
}
// 检查窗口是否满足恢复条件:不满足报警条件
if (!isValidPeriod(windowData, farBeyondValue, limitingValue, windowStart, windowEnd)) {
// 找到第一个不满足条件的点作为恢复开始时间
for (DataPoint point : windowData) {
if (point.value < limitingValue) {
return point.dateTime;
}
}
// 如果所有点都高于limitingValue但不满足其他条件,取窗口第一个点时间
return windowData.get(0).dateTime;
}
}
return null;
}
/**
* 检查是否满足报警条件
*/
private boolean isValidForAlarm(List<DataPoint> dataPoints,
double farBeyondValue,
double limitingValue) {
if (dataPoints.size() < MIN_DATA_POINTS) {
return false;
}
// 检查是否有至少24小时的连续数据满足条件
for (int i = 0; i < dataPoints.size(); i++) {
LocalDateTime windowStart = dataPoints.get(i).dateTime;
LocalDateTime windowEnd = windowStart.plusHours(HOURS_IN_DAY);
// 获取窗口内的数据点
List<DataPoint> windowData = new ArrayList<>();
for (int j = i; j < dataPoints.size(); j++) {
DataPoint point = dataPoints.get(j);
if (point.dateTime.isBefore(windowEnd)) {
windowData.add(point);
} else {
break;
}
}
if (isValidPeriod(windowData, farBeyondValue, limitingValue, windowStart, windowEnd)) {
return true;
}
}
return false;
}
// ===================== 报警记录管理 =====================
/**
* 创建报警记录
*/
private void createAlarmRecord(EquipmentparameterEntity equipment,
LocalDateTime startTime,
LocalDateTime endTime) {
try {
UleabnormalrecordsEntity record = new UleabnormalrecordsEntity();
record.setParacode(equipment.getEncode());
record.setAbnormaltime(toDate(startTime));
record.setCompletetime(toDate(endTime));
// 计算持续时间(分钟)
if (endTime != null) {
long durationSeconds = Duration.between(startTime, endTime).getSeconds();
record.setDuration((int) (durationSeconds / 60));
} else {
// 对于持续中的报警,计算从开始到现在的持续时间
long durationSeconds = Duration.between(startTime, LocalDateTime.now()).getSeconds();
record.setDuration((int) (durationSeconds / 60));
}
record.setAbnormaltype("700229026538590853");
record.setAbnormalstate(endTime == null ? "0" : "1"); // 0-报警中, 1-已结束
String processName = getProcessname(equipment.getEquipmentledgerid());
String equipName = getEquipname(equipment.getEquipmentledgerid());
if (endTime == null) {
record.setAbnormaldescribe(
"【" + processName + "】工序-【" + equipName + "】设备-【" + equipment.getFullname() +
"】参数,于(" + df.format(record.getAbnormaltime()) + ")出现高频高幅事件,请前往治理"
);
} else {
record.setAbnormaldescribe(
"【" + processName + "】工序-【" + equipName + "】设备-【" + equipment.getFullname() +
"】参数,于(" + df.format(record.getAbnormaltime()) + ")至(" +
df.format(record.getCompletetime()) + ")出现高频高幅事件"
);
}
record.setProcess(equipmentledgerService.getInfo(equipment.getEquipmentledgerid()).getProcesscode());
record.setEquipmentid(equipment.getEquipmentledgerid());
record.setEquipmenttype(equipmentledgerService.getInfo(equipment.getEquipmentledgerid()).getEquipmenttype());
record.setEquipmentcode(equipmentledgerService.getInfo(equipment.getEquipmentledgerid()).getDevicecode());
record.setParacode(equipment.getEncode());
record.setParaname(equipment.getFullname());
record.setAbnormalcode("7");
record.setCreatortime(new Date());
record.setCreatoruserid("349057407209541");
uleabnormalrecordsService.save(record);
if (endTime == null) {
logger.info("创建新报警记录: {} - 开始时间: {} (持续中)", equipment.getEncode(), startTime);
} else {
logger.info("创建完整报警记录: {} - 开始: {}, 结束: {} (持续{}小时)",
equipment.getEncode(), startTime, endTime, Duration.between(startTime, endTime).toHours());
}
} catch (Exception e) {
logger.error("创建报警记录失败: {}", e.getMessage(), e);
}
}
/**
* 完成报警处理
*/
private void completeAlarm(UleabnormalrecordsEntity alarm, LocalDateTime recoveryTime) {
try {
alarm.setCompletetime(toDate(recoveryTime));
LocalDateTime startTime = toLocalDateTime(alarm.getAbnormaltime());
long durationSeconds = Duration.between(startTime, recoveryTime).getSeconds();
alarm.setDuration((int) (durationSeconds / 60));
alarm.setAbnormalstate("1");
alarm.setLastmodifytime(new Date());
alarm.setLastmodifyuserid("349057407209541");
uleabnormalrecordsService.updateById(alarm);
long durationHours = Duration.between(startTime, recoveryTime).toHours();
logger.info("报警{}已恢复,开始时间: {},结束时间: {},持续小时: {}",
alarm.getId(), startTime, recoveryTime, durationHours);
} catch (Exception e) {
logger.error("完成报警处理失败: {}", e.getMessage(), e);
}
}
// ===================== 辅助方法 =====================
private List<DataPoint> prepareDataPoints(List<Map> hourDataList) {
return hourDataList.stream()
.map(map -> new DataPoint(
(String) map.get("datadt"),
((Number) map.get("avgdata")).doubleValue()
))
.collect(Collectors.toList());
}
private LocalDateTime findActualStartTime(List<DataPoint> dataPoints,
LocalDateTime windowStart,
double farBeyondValue,
double limitingValue) {
// 向前查找实际的异常开始时间
for (DataPoint point : dataPoints) {
if (point.dateTime.isAfter(windowStart)) {
break;
}
if (point.value >= limitingValue) {
return point.dateTime;
}
}
return windowStart;
}
private LocalDateTime findActualEndTime(List<DataPoint> dataPoints,
LocalDateTime windowEnd,
double farBeyondValue,
double limitingValue,
LocalDateTime analysisEnd) {
if (windowEnd == null) {
return null;
}
// 按时间排序数据点
dataPoints.sort(Comparator.comparing(DataPoint::getDateTime));
// 找到窗口结束时间后的第一个数据点索引
int startIndex = -1;
for (int i = 0; i < dataPoints.size(); i++) {
if (dataPoints.get(i).dateTime.isAfter(windowEnd)) {
startIndex = i;
break;
}
}
if (startIndex == -1) {
// 没有找到窗口结束时间后的数据点
return windowEnd;
}
// 按6小时分桶组织所有数据
Map<Integer, List<DataPoint>> bucketMap = new HashMap<>();
for (DataPoint point : dataPoints) {
int bucketIdx = point.dateTime.getHour() / 6;
bucketMap.computeIfAbsent(bucketIdx, k -> new ArrayList<>()).add(point);
}
// 检查每个时间点是否满足报警条件
for (int i = startIndex; i < dataPoints.size(); i++) {
DataPoint point = dataPoints.get(i);
// 检查条件1: 数据是否低于limitingValue
if (point.value < limitingValue) {
return point.dateTime;
}
// 检查条件2: 当前时间点所属的桶是否满足farBeyondValue条件
int currentBucket = point.dateTime.getHour() / 6;
List<DataPoint> bucketData = bucketMap.getOrDefault(currentBucket, new ArrayList<>());
// 检查当前桶内是否有数据点大于farBeyondValue
boolean hasFarBeyondValue = bucketData.stream()
.anyMatch(p -> p.value >= farBeyondValue);
// 如果当前桶内没有数据点达到farBeyondValue
if (!hasFarBeyondValue) {
// 查找当前桶内第一个数据点的时间
Optional<DataPoint> firstPointInBucket = bucketData.stream()
.min(Comparator.comparing(DataPoint::getDateTime));
if (firstPointInBucket.isPresent()) {
return firstPointInBucket.get().dateTime;
} else {
return point.dateTime;
}
}
}
// 如果没有找到不满足条件的点,返回窗口结束时间
return windowEnd;
}
private String formatDateTime(LocalDateTime dateTime) {
return dateTime.format(DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss"));
}
private Date toDate(LocalDateTime localDateTime) {
if (localDateTime == null) {
return null;
}
return Date.from(localDateTime.atZone(ZoneId.systemDefault()).toInstant());
}
private LocalDateTime toLocalDateTime(Date date) {
if (date == null) {
return null;
}
return LocalDateTime.ofInstant(date.toInstant(), ZoneId.systemDefault());
}
/**
* 合并连续的时间段
*/
private List<TimePeriod> mergeContinuousPeriods(List<TimePeriod> periods) {
if (periods.isEmpty()) {
return periods;
}
// 按开始时间排序
periods.sort(Comparator.comparing(p -> p.start));
List<TimePeriod> merged = new ArrayList<>();
TimePeriod current = periods.get(0);
for (int i = 1; i < periods.size(); i++) {
TimePeriod next = periods.get(i);
// 如果当前时间段结束时间与下一个时间段开始时间相差不超过24小时,则合并
if (current.end != null && next.start != null &&
Duration.between(current.end, next.start).toHours() <= 24) {
current.end = next.end;
} else {
merged.add(current);
current = next;
}
}
merged.add(current);
return merged;
}
// ===================== 辅助类 =====================
private static class DataPoint {
LocalDateTime dateTime;
double value;
DataPoint(String dateStr, double value) {
try {
// 尝试解析多种可能的时间格式
if (dateStr.contains("T")) {
// ISO格式: yyyy-MM-ddTHH:mm:ss
this.dateTime = LocalDateTime.parse(dateStr, DateTimeFormatter.ISO_LOCAL_DATE_TIME);
} else if (dateStr.length() == 16 && dateStr.contains(":")) {
// 格式: yyyy-MM-dd HH:mm
this.dateTime = LocalDateTime.parse(dateStr, DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm"));
} else if (dateStr.length() == 13 && dateStr.contains(" ")) {
// 格式: yyyy-MM-dd HH
this.dateTime = LocalDateTime.parse(dateStr + ":00:00",
DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss"));
} else if (dateStr.length() == 10 && dateStr.contains("-")) {
// 格式: yyyy-MM-dd
this.dateTime = LocalDateTime.parse(dateStr + " 00:00:00",
DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss"));
} else {
// 默认尝试ISO格式
this.dateTime = LocalDateTime.parse(dateStr, DateTimeFormatter.ISO_LOCAL_DATE_TIME);
}
} catch (Exception e) {
logger.error("解析时间字符串失败: {}", dateStr, e);
throw new RuntimeException("时间格式解析失败: " + dateStr);
}
this.value = value;
}
LocalDateTime getDateTime() {
return dateTime;
}
}
private static class TimePeriod {
LocalDateTime start;
LocalDateTime end; // null表示仍在持续
TimePeriod(LocalDateTime start, LocalDateTime end) {
this.start = start;
this.end = end;
}
}
/**
* 获取工序名称方法
* @param eid
* @return
*/
String getProcessname(String eid) {
try {
return processmanageService.getInfo(
equipmentledgerService.getInfo(eid).getProcesscode()
).getProcessname();
} catch (Exception e) {
logger.error("获取工序名称失败: {}", e.getMessage());
return "未知工序";
}
}
/**
* 获取设备名称方法
* @param eid
* @return
*/
String getEquipname(String eid) {
try {
return equipmentledgerService.getInfo(eid).getDevicename();
} catch (Exception e) {
logger.error("获取设备名称失败: {}", e.getMessage());
return "未知设备";
}
}
}
报警记录的结束时间的分析存在问题,报警结束时间应分析limitingValue值的条件和farBeyondValue值的条件。对每个点遍历分析limitingValue值不满足可直接返回,若limitingValue值满足farBeyondValue六个小时之内数据不满足,且不是第一桶,那要查找上一桶最后满足farBeyondValue时间,将他的下一小时返回,如果是第一桶,那返回本桶的第一个时间。