2026-01-30 17:37:27 +08:00
|
|
|
|
package com.klp.da.task;
|
|
|
|
|
|
|
|
|
|
|
|
import com.alibaba.fastjson2.JSON;
|
|
|
|
|
|
import com.klp.pocket.acid.domain.vo.AcidOeeDailySummaryVo;
|
|
|
|
|
|
import com.klp.pocket.acid.service.IAcidOeeService;
|
|
|
|
|
|
import lombok.Data;
|
|
|
|
|
|
import lombok.RequiredArgsConstructor;
|
|
|
|
|
|
import lombok.extern.slf4j.Slf4j;
|
|
|
|
|
|
import org.springframework.data.redis.core.StringRedisTemplate;
|
|
|
|
|
|
import org.springframework.scheduling.annotation.Scheduled;
|
|
|
|
|
|
import org.springframework.stereotype.Component;
|
|
|
|
|
|
|
|
|
|
|
|
import javax.annotation.PostConstruct;
|
|
|
|
|
|
import java.time.LocalDate;
|
|
|
|
|
|
import java.time.LocalDateTime;
|
|
|
|
|
|
import java.time.format.DateTimeFormatter;
|
|
|
|
|
|
import java.util.List;
|
|
|
|
|
|
import java.util.concurrent.TimeUnit;
|
|
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
|
* 酸轧线 OEE 当月预计算任务
|
|
|
|
|
|
*
|
|
|
|
|
|
* 需求对应 docs/oee-report-design.md 第 12.2 节:
|
|
|
|
|
|
* - 项目启动完成后即计算当月 OEE 聚合结果并写入 Redis;
|
|
|
|
|
|
* - 每天凌晨 04:00 重新计算当月数据并覆盖缓存。
|
|
|
|
|
|
*
|
2026-02-04 15:22:34 +08:00
|
|
|
|
* 当前仅实现酸轧线(SY)的当月日汇总预计算;
|
2026-01-30 17:37:27 +08:00
|
|
|
|
* key 约定:
|
|
|
|
|
|
* - 汇总结果:oee:report:month:summary:{yyyyMM}:SY
|
|
|
|
|
|
* - 元信息: oee:report:month:meta:{yyyyMM}:SY
|
|
|
|
|
|
*/
|
|
|
|
|
|
@Slf4j
|
|
|
|
|
|
@RequiredArgsConstructor
|
|
|
|
|
|
@Component
|
|
|
|
|
|
public class AcidOeeMonthTask {
|
|
|
|
|
|
|
|
|
|
|
|
/** Redis 缓存 key 模板:当月 OEE 汇总(酸轧线) */
|
|
|
|
|
|
private static final String SUMMARY_KEY_PATTERN = "oee:report:month:summary:%s:SY";
|
|
|
|
|
|
|
|
|
|
|
|
/** Redis 缓存 key 模板:当月元信息(酸轧线) */
|
|
|
|
|
|
private static final String META_KEY_PATTERN = "oee:report:month:meta:%s:SY";
|
|
|
|
|
|
|
|
|
|
|
|
private static final DateTimeFormatter YEAR_MONTH_FMT = DateTimeFormatter.ofPattern("yyyyMM");
|
|
|
|
|
|
private static final DateTimeFormatter DATE_FMT = DateTimeFormatter.ISO_DATE;
|
|
|
|
|
|
private static final DateTimeFormatter DATE_TIME_FMT = DateTimeFormatter.ISO_LOCAL_DATE_TIME;
|
|
|
|
|
|
|
|
|
|
|
|
private final IAcidOeeService acidOeeService;
|
|
|
|
|
|
private final StringRedisTemplate stringRedisTemplate;
|
|
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
|
* 项目启动完成后立即计算一次当月酸轧 OEE 汇总并写入 Redis。
|
|
|
|
|
|
*/
|
|
|
|
|
|
@PostConstruct
|
|
|
|
|
|
public void init() {
|
|
|
|
|
|
try {
|
|
|
|
|
|
computeCurrentMonth("startup");
|
|
|
|
|
|
} catch (Exception e) {
|
|
|
|
|
|
log.error("[AcidOeeMonthTask] startup compute failed", e);
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
|
* 每天凌晨 04:00 重新计算当月酸轧 OEE 汇总并覆盖 Redis 缓存。
|
|
|
|
|
|
*/
|
|
|
|
|
|
@Scheduled(cron = "0 0 4 * * ?")
|
|
|
|
|
|
public void scheduleDaily() {
|
|
|
|
|
|
try {
|
|
|
|
|
|
computeCurrentMonth("schedule-04");
|
|
|
|
|
|
} catch (Exception e) {
|
|
|
|
|
|
log.error("[AcidOeeMonthTask] 4am compute failed", e);
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
|
* 计算当前月份(从当月1号到今天)的酸轧 OEE 日汇总,并写入 Redis。
|
|
|
|
|
|
*
|
|
|
|
|
|
* @param trigger 触发来源标记(startup / schedule-04 等)
|
|
|
|
|
|
*/
|
|
|
|
|
|
private void computeCurrentMonth(String trigger) {
|
|
|
|
|
|
long startNs = System.nanoTime();
|
|
|
|
|
|
|
|
|
|
|
|
LocalDate now = LocalDate.now();
|
|
|
|
|
|
String yyyyMM = now.format(YEAR_MONTH_FMT);
|
|
|
|
|
|
|
|
|
|
|
|
LocalDate startDate = now.withDayOfMonth(1);
|
|
|
|
|
|
LocalDate endDate = now;
|
|
|
|
|
|
|
|
|
|
|
|
String startStr = startDate.format(DATE_FMT);
|
|
|
|
|
|
String endStr = endDate.format(DATE_FMT);
|
|
|
|
|
|
|
|
|
|
|
|
log.info("[AcidOeeMonthTask] trigger={}, computing acid OEE month summary for {} ({} ~ {})",
|
|
|
|
|
|
trigger, yyyyMM, startStr, endStr);
|
|
|
|
|
|
|
2026-02-04 15:22:34 +08:00
|
|
|
|
// 1. 调用 pocket 的 AcidOeeService 获取当月日汇总
|
2026-01-30 17:37:27 +08:00
|
|
|
|
List<AcidOeeDailySummaryVo> dailySummaryList = acidOeeService.getDailySummary(startStr, endStr);
|
|
|
|
|
|
|
|
|
|
|
|
// 2. 写入 Redis(summary)
|
|
|
|
|
|
String summaryKey = String.format(SUMMARY_KEY_PATTERN, yyyyMM);
|
|
|
|
|
|
String summaryJson = JSON.toJSONString(dailySummaryList);
|
|
|
|
|
|
stringRedisTemplate.opsForValue().set(summaryKey, summaryJson, 1, TimeUnit.DAYS);
|
|
|
|
|
|
|
|
|
|
|
|
long durationMs = (System.nanoTime() - startNs) / 1_000_000L;
|
|
|
|
|
|
|
|
|
|
|
|
// 3. 写入 Redis(meta)
|
|
|
|
|
|
Meta meta = new Meta();
|
|
|
|
|
|
meta.setComputedAt(LocalDateTime.now().format(DATE_TIME_FMT));
|
|
|
|
|
|
meta.setDurationMs(durationMs);
|
|
|
|
|
|
meta.setStartDate(startStr);
|
|
|
|
|
|
meta.setEndDate(endStr);
|
|
|
|
|
|
meta.setTrigger(trigger);
|
|
|
|
|
|
|
|
|
|
|
|
String metaKey = String.format(META_KEY_PATTERN, yyyyMM);
|
|
|
|
|
|
stringRedisTemplate.opsForValue().set(metaKey, JSON.toJSONString(meta), 1, TimeUnit.DAYS);
|
|
|
|
|
|
|
2026-02-04 15:22:34 +08:00
|
|
|
|
log.info("[AcidOeeMonthTask] compute finish for {} dailySize={}, durationMs={}ms, summaryKey={}",
|
|
|
|
|
|
yyyyMM, dailySummaryList.size(), durationMs, summaryKey);
|
2026-01-30 17:37:27 +08:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
|
* 当月预计算元信息
|
|
|
|
|
|
*/
|
|
|
|
|
|
@Data
|
|
|
|
|
|
private static class Meta {
|
|
|
|
|
|
/** 计算完成时间(ISO-8601 字符串) */
|
|
|
|
|
|
private String computedAt;
|
|
|
|
|
|
/** 计算耗时(毫秒) */
|
|
|
|
|
|
private long durationMs;
|
|
|
|
|
|
/** 统计起始日期(yyyy-MM-dd) */
|
|
|
|
|
|
private String startDate;
|
|
|
|
|
|
/** 统计结束日期(yyyy-MM-dd) */
|
|
|
|
|
|
private String endDate;
|
|
|
|
|
|
/** 触发来源(startup / schedule-04 等) */
|
|
|
|
|
|
private String trigger;
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|