|
|
@@ -1,499 +1,499 @@
|
|
|
-package com.ufo.project.forecast.fileupload.task;
|
|
|
-
|
|
|
-import java.io.File;
|
|
|
-import java.io.IOException;
|
|
|
-import java.nio.charset.StandardCharsets;
|
|
|
-import java.nio.file.Files;
|
|
|
-import java.time.Instant;
|
|
|
-import java.time.LocalDate;
|
|
|
-import java.time.LocalDateTime;
|
|
|
-import java.time.LocalTime;
|
|
|
-import java.time.ZoneId;
|
|
|
-import java.time.format.DateTimeFormatter;
|
|
|
-import java.util.ArrayList;
|
|
|
-import java.util.Collections;
|
|
|
-import java.util.Comparator;
|
|
|
-import java.util.List;
|
|
|
-import java.util.Locale;
|
|
|
-
|
|
|
-import com.alibaba.fastjson2.JSON;
|
|
|
-import org.slf4j.Logger;
|
|
|
-import org.slf4j.LoggerFactory;
|
|
|
-import org.springframework.beans.factory.annotation.Autowired;
|
|
|
-import org.springframework.beans.factory.annotation.Value;
|
|
|
-import org.springframework.scheduling.annotation.Scheduled;
|
|
|
-import org.springframework.stereotype.Component;
|
|
|
-
|
|
|
-import com.ufo.base.common.utils.StringUtils;
|
|
|
-import com.ufo.module.system.domain.SysDictData;
|
|
|
-import com.ufo.module.system.service.ISysDictTypeService;
|
|
|
-import com.ufo.project.config.domain.ConfigStation;
|
|
|
-import com.ufo.project.config.service.IConfigStationService;
|
|
|
-import com.ufo.project.forecast.fileupload.domain.DataPowerForecastReportBatch;
|
|
|
-import com.ufo.project.forecast.fileupload.service.IDataPowerForecastReportBatchService;
|
|
|
-import com.ufo.project.forecast.processor.ForecastProcessorFactory;
|
|
|
-import com.ufo.project.forecast.shortterm.power.domain.DataShortTermPowerForecastReport;
|
|
|
-import com.ufo.project.forecast.shortterm.power.mapper.DataShortTermPowerForecastReportMapper;
|
|
|
-import com.ufo.project.forecast.supershort.domain.DataSuperShortTermForecastReport;
|
|
|
-import com.ufo.project.forecast.supershort.mapper.DataSuperShortTermForecastReportMapper;
|
|
|
-
|
|
|
-/**
|
|
|
- * 功率预测上报 - 批次生成定时任务
|
|
|
- *
|
|
|
- * 读取字典 power_forecast_report_batch_config 中的场站配置(JSON数组),
|
|
|
- * 在每个预计上报时间前 initInterval 分钟窗口内生成上报批次行, 并触发对应处理器初始化上报数据.
|
|
|
- *
|
|
|
- * 配置示例:
|
|
|
- * <pre>
|
|
|
- * [
|
|
|
- * { "stationCode": "3301", "type": "short", "period": "daily", "times": ["08:00:00"], "initInterval": 60 }
|
|
|
- * ]
|
|
|
- * </pre>
|
|
|
- * initInterval 单位为分钟, 缺省 0.
|
|
|
- *
|
|
|
- * @author ufo
|
|
|
- * @date 2026-10-19
|
|
|
- */
|
|
|
-@Component
|
|
|
-public class DataPowerForecastReportBatchTask
|
|
|
-{
|
|
|
- private static final Logger log = LoggerFactory.getLogger(DataPowerForecastReportBatchTask.class);
|
|
|
-
|
|
|
- /** 上报批次配置字典类型 */
|
|
|
- public static final String DICT_TYPE = "power_forecast_report_batch_config";
|
|
|
-
|
|
|
- /** 扫描间隔(毫秒), 每轮结束后间隔5分钟 */
|
|
|
- private static final long SCAN_INTERVAL_MILLIS = 300_000L;
|
|
|
-
|
|
|
- /** 北京时间时区 */
|
|
|
- private static final ZoneId ZONE_SH = ZoneId.of("Asia/Shanghai");
|
|
|
-
|
|
|
- private static final DateTimeFormatter FMT_REPORT_DAY = DateTimeFormatter.ofPattern("yyyyMMdd");
|
|
|
-
|
|
|
- private static final DateTimeFormatter FMT_BATCH_NO = DateTimeFormatter.ofPattern("yyyyMMddHHmmss");
|
|
|
-
|
|
|
- /** 数据行时间格式(北京时间) */
|
|
|
- private static final DateTimeFormatter FMT_POINT_TIME = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss").withZone(ZONE_SH);
|
|
|
-
|
|
|
- /** 日期格式(yyyy-MM-dd) */
|
|
|
- private static final DateTimeFormatter FMT_DATE = DateTimeFormatter.ofPattern("yyyy-MM-dd");
|
|
|
-
|
|
|
- @Autowired
|
|
|
- private ISysDictTypeService dictTypeService;
|
|
|
-
|
|
|
- @Autowired
|
|
|
- private IConfigStationService configStationService;
|
|
|
-
|
|
|
- @Autowired
|
|
|
- private IDataPowerForecastReportBatchService reportBatchService;
|
|
|
-
|
|
|
- @Autowired
|
|
|
- private ForecastProcessorFactory factory;
|
|
|
-
|
|
|
- @Autowired
|
|
|
- private DataShortTermPowerForecastReportMapper shortTermReportMapper;
|
|
|
-
|
|
|
- @Autowired
|
|
|
- private DataSuperShortTermForecastReportMapper superShortTermReportMapper;
|
|
|
-
|
|
|
- @Value("${project.forecast.reportfile.rootfolder}")
|
|
|
- private String reportFileRootFolder;
|
|
|
-
|
|
|
- /**
|
|
|
- * 扫描字典配置, 为窗口内的预计上报时点生成批次行并触发数据初始化
|
|
|
- */
|
|
|
- @Scheduled(fixedDelay = SCAN_INTERVAL_MILLIS)
|
|
|
- public void autoGenerateBatchNo()
|
|
|
- {
|
|
|
- List<Config> configs = loadConfigs();
|
|
|
- if (configs.isEmpty())
|
|
|
- {
|
|
|
- return;
|
|
|
- }
|
|
|
- for (Config config : configs)
|
|
|
- {
|
|
|
- try
|
|
|
- {
|
|
|
- process(config);
|
|
|
- }
|
|
|
- catch (Exception e)
|
|
|
- {
|
|
|
- log.error("[PowerForecastReportBatch] 处理配置项失败, stationCode={}, type={}",
|
|
|
- config == null ? null : config.getStationCode(), config == null ? null : config.getType(), e);
|
|
|
- }
|
|
|
- }
|
|
|
- }
|
|
|
-
|
|
|
- /**
|
|
|
- * 状态推进: 2已确认 -> 4文件上传中 (每分钟第23秒)
|
|
|
- */
|
|
|
- // @Scheduled(cron = "23 * * * * *")
|
|
|
- public void startingFileGenerating()
|
|
|
- {
|
|
|
- DataPowerForecastReportBatch q = new DataPowerForecastReportBatch();
|
|
|
- q.setStatus(DataPowerForecastReportBatch.STATUS_CONFIRMED);
|
|
|
- List<DataPowerForecastReportBatch> batches = reportBatchService.selectDataPowerForecastReportBatchList(q);
|
|
|
- if (batches == null || batches.isEmpty())
|
|
|
- {
|
|
|
- return;
|
|
|
- }
|
|
|
- for (DataPowerForecastReportBatch b : batches)
|
|
|
- {
|
|
|
- try
|
|
|
- {
|
|
|
- DataPowerForecastReportBatch u = new DataPowerForecastReportBatch();
|
|
|
- u.setId(b.getId());
|
|
|
- u.setStatus(DataPowerForecastReportBatch.STATUS_FILE_UPLOADING);
|
|
|
- reportBatchService.updateDataPowerForecastReportBatch(u);
|
|
|
- log.info("[PowerForecastReportBatch] 状态 2->4, batchNo={}", b.getBatchNo());
|
|
|
- }
|
|
|
- catch (Exception e)
|
|
|
- {
|
|
|
- log.error("[PowerForecastReportBatch] 状态 2->4 失败, batchNo={}", b.getBatchNo(), e);
|
|
|
- }
|
|
|
- }
|
|
|
- }
|
|
|
-
|
|
|
- /**
|
|
|
- * 生成上报文件: 4文件上传中 -> 5文件上传成功 / 9文件上传失败 (每分钟第45秒)
|
|
|
- */
|
|
|
- // @Scheduled(cron = "45 * * * * *")
|
|
|
- public void generateReportFile()
|
|
|
- {
|
|
|
- DataPowerForecastReportBatch q = new DataPowerForecastReportBatch();
|
|
|
- q.setStatus(DataPowerForecastReportBatch.STATUS_FILE_UPLOADING);
|
|
|
- List<DataPowerForecastReportBatch> batches = reportBatchService.selectDataPowerForecastReportBatchList(q);
|
|
|
- if (batches == null || batches.isEmpty())
|
|
|
- {
|
|
|
- return;
|
|
|
- }
|
|
|
- for (DataPowerForecastReportBatch b : batches)
|
|
|
- {
|
|
|
- try
|
|
|
- {
|
|
|
- File file = buildReportFile(b);
|
|
|
- DataPowerForecastReportBatch u = new DataPowerForecastReportBatch();
|
|
|
- u.setId(b.getId());
|
|
|
- u.setFile(file.getAbsolutePath());
|
|
|
- u.setStatus(DataPowerForecastReportBatch.STATUS_FILE_UPLOAD_SUCCESS);
|
|
|
- reportBatchService.updateDataPowerForecastReportBatch(u);
|
|
|
- log.info("[PowerForecastReportBatch] 上报文件生成成功, batchNo={}, file={}",
|
|
|
- b.getBatchNo(), file.getAbsolutePath());
|
|
|
- }
|
|
|
- catch (Exception e)
|
|
|
- {
|
|
|
- log.error("[PowerForecastReportBatch] 上报文件生成失败, batchNo={}", b.getBatchNo(), e);
|
|
|
- DataPowerForecastReportBatch u = new DataPowerForecastReportBatch();
|
|
|
- u.setId(b.getId());
|
|
|
- u.setStatus(DataPowerForecastReportBatch.STATUS_FILE_UPLOAD_FAILED);
|
|
|
- try
|
|
|
- {
|
|
|
- reportBatchService.updateDataPowerForecastReportBatch(u);
|
|
|
- }
|
|
|
- catch (Exception ex)
|
|
|
- {
|
|
|
- log.error("[PowerForecastReportBatch] 状态置9失败, batchNo={}", b.getBatchNo(), ex);
|
|
|
- }
|
|
|
- }
|
|
|
- }
|
|
|
- }
|
|
|
-
|
|
|
- /**
|
|
|
- * 生成 .dat 上报文件并返回文件对象(异常向上抛, 由调用方置状态9)
|
|
|
- */
|
|
|
- private File buildReportFile(DataPowerForecastReportBatch batch) throws IOException
|
|
|
- {
|
|
|
- List<ReportPoint> points = loadReportPoints(batch);
|
|
|
- if (points.isEmpty())
|
|
|
- {
|
|
|
- throw new IllegalStateException("批次无上报数据, batchNo=" + batch.getBatchNo());
|
|
|
- }
|
|
|
- ConfigStation sq = new ConfigStation();
|
|
|
- sq.setStationCode(batch.getStationCode());
|
|
|
- List<ConfigStation> stations = configStationService.selectConfigStationList(sq);
|
|
|
- if (stations == null || stations.isEmpty())
|
|
|
- {
|
|
|
- throw new IllegalStateException("未找到场站, stationCode=" + batch.getStationCode());
|
|
|
- }
|
|
|
- Long capacity = stations.get(0).getInstalledCapacity();
|
|
|
- if (capacity == null)
|
|
|
- {
|
|
|
- throw new IllegalStateException("场站装机容量为空, stationCode=" + batch.getStationCode());
|
|
|
- }
|
|
|
- String marker = DataPowerForecastReportBatch.TYPE_ULTRA.equals(batch.getType()) ? "CDQYC" : "DQYC";
|
|
|
- String fileName = "GF_" + batch.getStationName() + "_" + marker + "_" + batch.getReportDay()
|
|
|
- + "_" + batch.getEstReportTime().replace(":", "") + ".dat";
|
|
|
- int reportDay = batch.getReportDay();
|
|
|
- String year = String.valueOf(reportDay / 10000);
|
|
|
- String month = String.format(Locale.ROOT, "%02d", (reportDay / 100) % 100);
|
|
|
- File dir = new File(reportFileRootFolder,
|
|
|
- batch.getType() + File.separator + batch.getStationCode()
|
|
|
- + File.separator + year + File.separator + month);
|
|
|
- if (!dir.exists() && !dir.mkdirs())
|
|
|
- {
|
|
|
- throw new IOException("创建目录失败: " + dir.getAbsolutePath());
|
|
|
- }
|
|
|
- File target = new File(dir, fileName);
|
|
|
- StringBuilder sb = new StringBuilder();
|
|
|
- sb.append("<! System=PowerForecast, Version=1.0, Code=UTF-8, Data=").append(batch.getReportDay()).append(" !>\n");
|
|
|
- sb.append('<').append(marker).append("::").append(batch.getStationName()).append(">\n");
|
|
|
- sb.append("Date=").append(LocalDate.parse(String.valueOf(batch.getReportDay()), FMT_REPORT_DAY).format(FMT_DATE))
|
|
|
- .append(", Time=").append(batch.getEstReportTime().replace(":", "-")).append('\n');
|
|
|
- sb.append("# 点号\t时间\t预测功率(MW)\t预计开机容量(MW)\t备注\n");
|
|
|
- String capacityMw = String.format(Locale.ROOT, "%.2f", capacity / 1000.0);
|
|
|
- for (int i = 0; i < points.size(); i++)
|
|
|
- {
|
|
|
- ReportPoint p = points.get(i);
|
|
|
- sb.append(i + 1).append('\t')
|
|
|
- .append(FMT_POINT_TIME.format(Instant.ofEpochSecond(p.forecastTime))).append('\t')
|
|
|
- .append(String.format(Locale.ROOT, "%.2f", p.power / 1000.0)).append('\t')
|
|
|
- .append(capacityMw).append('\t')
|
|
|
- .append("正常").append('\n');
|
|
|
- }
|
|
|
- sb.append("</").append(marker).append("::").append(batch.getStationName()).append(">\n");
|
|
|
- Files.write(target.toPath(), sb.toString().getBytes(StandardCharsets.UTF_8));
|
|
|
- return target;
|
|
|
- }
|
|
|
-
|
|
|
- /**
|
|
|
- * 按批次号加载上报数据点, 按预测时刻升序(power 为 kW 原始值)
|
|
|
- */
|
|
|
- private List<ReportPoint> loadReportPoints(DataPowerForecastReportBatch batch)
|
|
|
- {
|
|
|
- List<ReportPoint> points = new ArrayList<>();
|
|
|
- if (DataPowerForecastReportBatch.TYPE_ULTRA.equals(batch.getType()))
|
|
|
- {
|
|
|
- DataSuperShortTermForecastReport q = new DataSuperShortTermForecastReport();
|
|
|
- q.setBatchNo(batch.getBatchNo());
|
|
|
- for (DataSuperShortTermForecastReport r : superShortTermReportMapper.selectDataSuperShortTermForecastReportList(q))
|
|
|
- {
|
|
|
- if (r.getForecastTime() != null && StringUtils.isNotBlank(r.getPower()))
|
|
|
- {
|
|
|
- points.add(new ReportPoint(r.getForecastTime(), Double.parseDouble(r.getPower())));
|
|
|
- }
|
|
|
- }
|
|
|
- }
|
|
|
- else
|
|
|
- {
|
|
|
- DataShortTermPowerForecastReport q = new DataShortTermPowerForecastReport();
|
|
|
- q.setBatchNo(batch.getBatchNo());
|
|
|
- for (DataShortTermPowerForecastReport r : shortTermReportMapper.selectDataShortTermPowerForecastReportList(q))
|
|
|
- {
|
|
|
- if (r.getForecastTime() != null && StringUtils.isNotBlank(r.getPower()))
|
|
|
- {
|
|
|
- points.add(new ReportPoint(r.getForecastTime(), Double.parseDouble(r.getPower())));
|
|
|
- }
|
|
|
- }
|
|
|
- }
|
|
|
- points.sort(Comparator.comparingLong(p -> p.forecastTime));
|
|
|
- return points;
|
|
|
- }
|
|
|
-
|
|
|
- /**
|
|
|
- * 上报数据点: 预测时刻(UTC秒) + 功率(kW)
|
|
|
- */
|
|
|
- private static class ReportPoint
|
|
|
- {
|
|
|
- private final long forecastTime;
|
|
|
-
|
|
|
- private final double power;
|
|
|
-
|
|
|
- ReportPoint(long forecastTime, double power)
|
|
|
- {
|
|
|
- this.forecastTime = forecastTime;
|
|
|
- this.power = power;
|
|
|
- }
|
|
|
- }
|
|
|
-
|
|
|
- /**
|
|
|
- * 读取字典配置, 解析为场站配置列表
|
|
|
- */
|
|
|
- private List<Config> loadConfigs()
|
|
|
- {
|
|
|
- try
|
|
|
- {
|
|
|
- List<SysDictData> dictList = dictTypeService.selectDictDataByType(DICT_TYPE);
|
|
|
- if (dictList == null || dictList.isEmpty())
|
|
|
- {
|
|
|
- return Collections.emptyList();
|
|
|
- }
|
|
|
- String dictValue = dictList.get(0).getDictValue();
|
|
|
- if (StringUtils.isBlank(dictValue))
|
|
|
- {
|
|
|
- return Collections.emptyList();
|
|
|
- }
|
|
|
- List<Config> configs = JSON.parseArray(dictValue, Config.class);
|
|
|
- return configs == null ? Collections.<Config>emptyList() : configs;
|
|
|
- }
|
|
|
- catch (Exception e)
|
|
|
- {
|
|
|
- log.error("[PowerForecastReportBatch] 解析字典 {} 配置失败", DICT_TYPE, e);
|
|
|
- return Collections.emptyList();
|
|
|
- }
|
|
|
- }
|
|
|
-
|
|
|
- /**
|
|
|
- * 处理单个场站配置: 遍历预计上报时点(升序), 在提前窗口内生成批次行并触发初始化
|
|
|
- */
|
|
|
- private void process(Config config)
|
|
|
- {
|
|
|
- if (config == null || StringUtils.isBlank(config.getStationCode()))
|
|
|
- {
|
|
|
- return;
|
|
|
- }
|
|
|
- if (!"daily".equals(config.getPeriod()))
|
|
|
- {
|
|
|
- log.warn("[PowerForecastReportBatch] period 非 daily, 跳过, stationCode={}", config.getStationCode());
|
|
|
- return;
|
|
|
- }
|
|
|
- if (!DataPowerForecastReportBatch.TYPE_SHORT.equals(config.getType())
|
|
|
- && !DataPowerForecastReportBatch.TYPE_ULTRA.equals(config.getType()))
|
|
|
- {
|
|
|
- log.warn("[PowerForecastReportBatch] type 未知, 跳过, stationCode={}, type={}",
|
|
|
- config.getStationCode(), config.getType());
|
|
|
- return;
|
|
|
- }
|
|
|
- ConfigStation q = new ConfigStation();
|
|
|
- q.setStationCode(config.getStationCode());
|
|
|
- List<ConfigStation> stations = configStationService.selectConfigStationList(q);
|
|
|
- if (stations == null || stations.isEmpty())
|
|
|
- {
|
|
|
- log.warn("[PowerForecastReportBatch] 未找到场站, 跳过, stationCode={}", config.getStationCode());
|
|
|
- return;
|
|
|
- }
|
|
|
- String stationName = stations.get(0).getStationName();
|
|
|
- List<String> times = config.getTimes();
|
|
|
- if (times == null || times.isEmpty())
|
|
|
- {
|
|
|
- log.warn("[PowerForecastReportBatch] times 为空, 跳过, stationCode={}", config.getStationCode());
|
|
|
- return;
|
|
|
- }
|
|
|
- times.sort(Comparator.naturalOrder());
|
|
|
- for (String t : times)
|
|
|
- {
|
|
|
- LocalTime slotTime;
|
|
|
- try
|
|
|
- {
|
|
|
- slotTime = LocalTime.parse(t);
|
|
|
- }
|
|
|
- catch (Exception e)
|
|
|
- {
|
|
|
- log.warn("[PowerForecastReportBatch] 时点格式非法, 跳过, stationCode={}, time={}",
|
|
|
- config.getStationCode(), t);
|
|
|
- continue;
|
|
|
- }
|
|
|
- LocalDateTime now = LocalDateTime.now(ZONE_SH);
|
|
|
- LocalDate today = LocalDate.now(ZONE_SH);
|
|
|
- LocalDateTime slot = today.atTime(slotTime);
|
|
|
- // 已过时点, 跳过后续更远的时点
|
|
|
- if (now.isAfter(slot))
|
|
|
- {
|
|
|
- continue;
|
|
|
- }
|
|
|
- // 未到提前窗口, 后续时点更远, 直接结束
|
|
|
- if (now.isBefore(slot.minusMinutes(config.getInitInterval() == null ? 0 : config.getInitInterval())))
|
|
|
- {
|
|
|
- break;
|
|
|
- }
|
|
|
- int reportDay = Integer.parseInt(today.format(FMT_REPORT_DAY));
|
|
|
- boolean exists = reportBatchService.selectByTypeDayTime(config.getType(), reportDay, t)
|
|
|
- .stream().anyMatch(b -> config.getStationCode().equals(b.getStationCode()));
|
|
|
- if (exists)
|
|
|
- {
|
|
|
- continue;
|
|
|
- }
|
|
|
- DataPowerForecastReportBatch b = new DataPowerForecastReportBatch();
|
|
|
- b.setStationCode(config.getStationCode());
|
|
|
- b.setStationName(stationName);
|
|
|
- b.setType(config.getType());
|
|
|
- b.setReportDay(reportDay);
|
|
|
- b.setEstReportTime(t);
|
|
|
- b.setStatus(DataPowerForecastReportBatch.STATUS_PENDING);
|
|
|
- b.setGenerateSource("auto");
|
|
|
- b.setBatchNo(prefix(config.getType()) + slot.format(FMT_BATCH_NO) + "_" + config.getStationCode());
|
|
|
- reportBatchService.insertDataPowerForecastReportBatch(b);
|
|
|
- log.info("[PowerForecastReportBatch] 新生成上报批次, batchNo={}, stationCode={}, time={}",
|
|
|
- b.getBatchNo(), config.getStationCode(), t);
|
|
|
- factory.getInstant(config.getType()).initData(reportDay, t);
|
|
|
- }
|
|
|
- }
|
|
|
-
|
|
|
- /**
|
|
|
- * 批次号前缀: 超短期 ULT, 其余 ST
|
|
|
- */
|
|
|
- private static String prefix(String type)
|
|
|
- {
|
|
|
- return "ultra".equals(type) ? "ULT" : "ST";
|
|
|
- }
|
|
|
-
|
|
|
- /**
|
|
|
- * 字典 power_forecast_report_batch_config 的单个场站配置
|
|
|
- */
|
|
|
- public static class Config
|
|
|
- {
|
|
|
- /** 场站编码 */
|
|
|
- private String stationCode;
|
|
|
-
|
|
|
- /** 类型(short短期,ultra超短期) */
|
|
|
- private String type;
|
|
|
-
|
|
|
- /** 周期(daily) */
|
|
|
- private String period;
|
|
|
-
|
|
|
- /** 预计上报时点列表(HH:mm:ss) */
|
|
|
- private List<String> times;
|
|
|
-
|
|
|
- /** 提前初始化窗口(分钟), 缺省 0 */
|
|
|
- private Integer initInterval;
|
|
|
-
|
|
|
- public String getStationCode()
|
|
|
- {
|
|
|
- return stationCode;
|
|
|
- }
|
|
|
-
|
|
|
- public void setStationCode(String stationCode)
|
|
|
- {
|
|
|
- this.stationCode = stationCode;
|
|
|
- }
|
|
|
-
|
|
|
- public String getType()
|
|
|
- {
|
|
|
- return type;
|
|
|
- }
|
|
|
-
|
|
|
- public void setType(String type)
|
|
|
- {
|
|
|
- this.type = type;
|
|
|
- }
|
|
|
-
|
|
|
- public String getPeriod()
|
|
|
- {
|
|
|
- return period;
|
|
|
- }
|
|
|
-
|
|
|
- public void setPeriod(String period)
|
|
|
- {
|
|
|
- this.period = period;
|
|
|
- }
|
|
|
-
|
|
|
- public List<String> getTimes()
|
|
|
- {
|
|
|
- return times;
|
|
|
- }
|
|
|
-
|
|
|
- public void setTimes(List<String> times)
|
|
|
- {
|
|
|
- this.times = times;
|
|
|
- }
|
|
|
-
|
|
|
- public Integer getInitInterval()
|
|
|
- {
|
|
|
- return initInterval;
|
|
|
- }
|
|
|
-
|
|
|
- public void setInitInterval(Integer initInterval)
|
|
|
- {
|
|
|
- this.initInterval = initInterval;
|
|
|
- }
|
|
|
- }
|
|
|
-}
|
|
|
+// package com.ufo.project.forecast.fileupload.task;
|
|
|
+
|
|
|
+// import java.io.File;
|
|
|
+// import java.io.IOException;
|
|
|
+// import java.nio.charset.StandardCharsets;
|
|
|
+// import java.nio.file.Files;
|
|
|
+// import java.time.Instant;
|
|
|
+// import java.time.LocalDate;
|
|
|
+// import java.time.LocalDateTime;
|
|
|
+// import java.time.LocalTime;
|
|
|
+// import java.time.ZoneId;
|
|
|
+// import java.time.format.DateTimeFormatter;
|
|
|
+// import java.util.ArrayList;
|
|
|
+// import java.util.Collections;
|
|
|
+// import java.util.Comparator;
|
|
|
+// import java.util.List;
|
|
|
+// import java.util.Locale;
|
|
|
+
|
|
|
+// import com.alibaba.fastjson2.JSON;
|
|
|
+// import org.slf4j.Logger;
|
|
|
+// import org.slf4j.LoggerFactory;
|
|
|
+// import org.springframework.beans.factory.annotation.Autowired;
|
|
|
+// import org.springframework.beans.factory.annotation.Value;
|
|
|
+// import org.springframework.scheduling.annotation.Scheduled;
|
|
|
+// import org.springframework.stereotype.Component;
|
|
|
+
|
|
|
+// import com.ufo.base.common.utils.StringUtils;
|
|
|
+// import com.ufo.module.system.domain.SysDictData;
|
|
|
+// import com.ufo.module.system.service.ISysDictTypeService;
|
|
|
+// import com.ufo.project.config.domain.ConfigStation;
|
|
|
+// import com.ufo.project.config.service.IConfigStationService;
|
|
|
+// import com.ufo.project.forecast.fileupload.domain.DataPowerForecastReportBatch;
|
|
|
+// import com.ufo.project.forecast.fileupload.service.IDataPowerForecastReportBatchService;
|
|
|
+// import com.ufo.project.forecast.processor.ForecastProcessorFactory;
|
|
|
+// import com.ufo.project.forecast.shortterm.power.domain.DataShortTermPowerForecastReport;
|
|
|
+// import com.ufo.project.forecast.shortterm.power.mapper.DataShortTermPowerForecastReportMapper;
|
|
|
+// import com.ufo.project.forecast.supershort.domain.DataSuperShortTermForecastReport;
|
|
|
+// import com.ufo.project.forecast.supershort.mapper.DataSuperShortTermForecastReportMapper;
|
|
|
+
|
|
|
+// /**
|
|
|
+// * 功率预测上报 - 批次生成定时任务
|
|
|
+// *
|
|
|
+// * 读取字典 power_forecast_report_batch_config 中的场站配置(JSON数组),
|
|
|
+// * 在每个预计上报时间前 initInterval 分钟窗口内生成上报批次行, 并触发对应处理器初始化上报数据.
|
|
|
+// *
|
|
|
+// * 配置示例:
|
|
|
+// * <pre>
|
|
|
+// * [
|
|
|
+// * { "stationCode": "3301", "type": "short", "period": "daily", "times": ["08:00:00"], "initInterval": 60 }
|
|
|
+// * ]
|
|
|
+// * </pre>
|
|
|
+// * initInterval 单位为分钟, 缺省 0.
|
|
|
+// *
|
|
|
+// * @author ufo
|
|
|
+// * @date 2026-10-19
|
|
|
+// */
|
|
|
+// @Component
|
|
|
+// public class DataPowerForecastReportBatchTask
|
|
|
+// {
|
|
|
+// private static final Logger log = LoggerFactory.getLogger(DataPowerForecastReportBatchTask.class);
|
|
|
+
|
|
|
+// /** 上报批次配置字典类型 */
|
|
|
+// public static final String DICT_TYPE = "power_forecast_report_batch_config";
|
|
|
+
|
|
|
+// /** 扫描间隔(毫秒), 每轮结束后间隔5分钟 */
|
|
|
+// private static final long SCAN_INTERVAL_MILLIS = 300_000L;
|
|
|
+
|
|
|
+// /** 北京时间时区 */
|
|
|
+// private static final ZoneId ZONE_SH = ZoneId.of("Asia/Shanghai");
|
|
|
+
|
|
|
+// private static final DateTimeFormatter FMT_REPORT_DAY = DateTimeFormatter.ofPattern("yyyyMMdd");
|
|
|
+
|
|
|
+// private static final DateTimeFormatter FMT_BATCH_NO = DateTimeFormatter.ofPattern("yyyyMMddHHmmss");
|
|
|
+
|
|
|
+// /** 数据行时间格式(北京时间) */
|
|
|
+// private static final DateTimeFormatter FMT_POINT_TIME = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss").withZone(ZONE_SH);
|
|
|
+
|
|
|
+// /** 日期格式(yyyy-MM-dd) */
|
|
|
+// private static final DateTimeFormatter FMT_DATE = DateTimeFormatter.ofPattern("yyyy-MM-dd");
|
|
|
+
|
|
|
+// @Autowired
|
|
|
+// private ISysDictTypeService dictTypeService;
|
|
|
+
|
|
|
+// @Autowired
|
|
|
+// private IConfigStationService configStationService;
|
|
|
+
|
|
|
+// @Autowired
|
|
|
+// private IDataPowerForecastReportBatchService reportBatchService;
|
|
|
+
|
|
|
+// @Autowired
|
|
|
+// private ForecastProcessorFactory factory;
|
|
|
+
|
|
|
+// @Autowired
|
|
|
+// private DataShortTermPowerForecastReportMapper shortTermReportMapper;
|
|
|
+
|
|
|
+// @Autowired
|
|
|
+// private DataSuperShortTermForecastReportMapper superShortTermReportMapper;
|
|
|
+
|
|
|
+// @Value("${project.forecast.reportfile.rootfolder}")
|
|
|
+// private String reportFileRootFolder;
|
|
|
+
|
|
|
+// /**
|
|
|
+// * 扫描字典配置, 为窗口内的预计上报时点生成批次行并触发数据初始化
|
|
|
+// */
|
|
|
+// @Scheduled(fixedDelay = SCAN_INTERVAL_MILLIS)
|
|
|
+// public void autoGenerateBatchNo()
|
|
|
+// {
|
|
|
+// List<Config> configs = loadConfigs();
|
|
|
+// if (configs.isEmpty())
|
|
|
+// {
|
|
|
+// return;
|
|
|
+// }
|
|
|
+// for (Config config : configs)
|
|
|
+// {
|
|
|
+// try
|
|
|
+// {
|
|
|
+// process(config);
|
|
|
+// }
|
|
|
+// catch (Exception e)
|
|
|
+// {
|
|
|
+// log.error("[PowerForecastReportBatch] 处理配置项失败, stationCode={}, type={}",
|
|
|
+// config == null ? null : config.getStationCode(), config == null ? null : config.getType(), e);
|
|
|
+// }
|
|
|
+// }
|
|
|
+// }
|
|
|
+
|
|
|
+// /**
|
|
|
+// * 状态推进: 2已确认 -> 4文件上传中 (每分钟第23秒)
|
|
|
+// */
|
|
|
+// // @Scheduled(cron = "23 * * * * *")
|
|
|
+// public void startingFileGenerating()
|
|
|
+// {
|
|
|
+// DataPowerForecastReportBatch q = new DataPowerForecastReportBatch();
|
|
|
+// q.setStatus(DataPowerForecastReportBatch.STATUS_CONFIRMED);
|
|
|
+// List<DataPowerForecastReportBatch> batches = reportBatchService.selectDataPowerForecastReportBatchList(q);
|
|
|
+// if (batches == null || batches.isEmpty())
|
|
|
+// {
|
|
|
+// return;
|
|
|
+// }
|
|
|
+// for (DataPowerForecastReportBatch b : batches)
|
|
|
+// {
|
|
|
+// try
|
|
|
+// {
|
|
|
+// DataPowerForecastReportBatch u = new DataPowerForecastReportBatch();
|
|
|
+// u.setId(b.getId());
|
|
|
+// u.setStatus(DataPowerForecastReportBatch.STATUS_FILE_UPLOADING);
|
|
|
+// reportBatchService.updateDataPowerForecastReportBatch(u);
|
|
|
+// log.info("[PowerForecastReportBatch] 状态 2->4, batchNo={}", b.getBatchNo());
|
|
|
+// }
|
|
|
+// catch (Exception e)
|
|
|
+// {
|
|
|
+// log.error("[PowerForecastReportBatch] 状态 2->4 失败, batchNo={}", b.getBatchNo(), e);
|
|
|
+// }
|
|
|
+// }
|
|
|
+// }
|
|
|
+
|
|
|
+// /**
|
|
|
+// * 生成上报文件: 4文件上传中 -> 5文件上传成功 / 9文件上传失败 (每分钟第45秒)
|
|
|
+// */
|
|
|
+// // @Scheduled(cron = "45 * * * * *")
|
|
|
+// public void generateReportFile()
|
|
|
+// {
|
|
|
+// DataPowerForecastReportBatch q = new DataPowerForecastReportBatch();
|
|
|
+// q.setStatus(DataPowerForecastReportBatch.STATUS_FILE_UPLOADING);
|
|
|
+// List<DataPowerForecastReportBatch> batches = reportBatchService.selectDataPowerForecastReportBatchList(q);
|
|
|
+// if (batches == null || batches.isEmpty())
|
|
|
+// {
|
|
|
+// return;
|
|
|
+// }
|
|
|
+// for (DataPowerForecastReportBatch b : batches)
|
|
|
+// {
|
|
|
+// try
|
|
|
+// {
|
|
|
+// File file = buildReportFile(b);
|
|
|
+// DataPowerForecastReportBatch u = new DataPowerForecastReportBatch();
|
|
|
+// u.setId(b.getId());
|
|
|
+// u.setFile(file.getAbsolutePath());
|
|
|
+// u.setStatus(DataPowerForecastReportBatch.STATUS_FILE_UPLOAD_SUCCESS);
|
|
|
+// reportBatchService.updateDataPowerForecastReportBatch(u);
|
|
|
+// log.info("[PowerForecastReportBatch] 上报文件生成成功, batchNo={}, file={}",
|
|
|
+// b.getBatchNo(), file.getAbsolutePath());
|
|
|
+// }
|
|
|
+// catch (Exception e)
|
|
|
+// {
|
|
|
+// log.error("[PowerForecastReportBatch] 上报文件生成失败, batchNo={}", b.getBatchNo(), e);
|
|
|
+// DataPowerForecastReportBatch u = new DataPowerForecastReportBatch();
|
|
|
+// u.setId(b.getId());
|
|
|
+// u.setStatus(DataPowerForecastReportBatch.STATUS_FILE_UPLOAD_FAILED);
|
|
|
+// try
|
|
|
+// {
|
|
|
+// reportBatchService.updateDataPowerForecastReportBatch(u);
|
|
|
+// }
|
|
|
+// catch (Exception ex)
|
|
|
+// {
|
|
|
+// log.error("[PowerForecastReportBatch] 状态置9失败, batchNo={}", b.getBatchNo(), ex);
|
|
|
+// }
|
|
|
+// }
|
|
|
+// }
|
|
|
+// }
|
|
|
+
|
|
|
+// /**
|
|
|
+// * 生成 .dat 上报文件并返回文件对象(异常向上抛, 由调用方置状态9)
|
|
|
+// */
|
|
|
+// private File buildReportFile(DataPowerForecastReportBatch batch) throws IOException
|
|
|
+// {
|
|
|
+// List<ReportPoint> points = loadReportPoints(batch);
|
|
|
+// if (points.isEmpty())
|
|
|
+// {
|
|
|
+// throw new IllegalStateException("批次无上报数据, batchNo=" + batch.getBatchNo());
|
|
|
+// }
|
|
|
+// ConfigStation sq = new ConfigStation();
|
|
|
+// sq.setStationCode(batch.getStationCode());
|
|
|
+// List<ConfigStation> stations = configStationService.selectConfigStationList(sq);
|
|
|
+// if (stations == null || stations.isEmpty())
|
|
|
+// {
|
|
|
+// throw new IllegalStateException("未找到场站, stationCode=" + batch.getStationCode());
|
|
|
+// }
|
|
|
+// Long capacity = stations.get(0).getInstalledCapacity();
|
|
|
+// if (capacity == null)
|
|
|
+// {
|
|
|
+// throw new IllegalStateException("场站装机容量为空, stationCode=" + batch.getStationCode());
|
|
|
+// }
|
|
|
+// String marker = DataPowerForecastReportBatch.TYPE_ULTRA.equals(batch.getType()) ? "CDQYC" : "DQYC";
|
|
|
+// String fileName = "GF_" + batch.getStationName() + "_" + marker + "_" + batch.getReportDay()
|
|
|
+// + "_" + batch.getEstReportTime().replace(":", "") + ".dat";
|
|
|
+// int reportDay = batch.getReportDay();
|
|
|
+// String year = String.valueOf(reportDay / 10000);
|
|
|
+// String month = String.format(Locale.ROOT, "%02d", (reportDay / 100) % 100);
|
|
|
+// File dir = new File(reportFileRootFolder,
|
|
|
+// batch.getType() + File.separator + batch.getStationCode()
|
|
|
+// + File.separator + year + File.separator + month);
|
|
|
+// if (!dir.exists() && !dir.mkdirs())
|
|
|
+// {
|
|
|
+// throw new IOException("创建目录失败: " + dir.getAbsolutePath());
|
|
|
+// }
|
|
|
+// File target = new File(dir, fileName);
|
|
|
+// StringBuilder sb = new StringBuilder();
|
|
|
+// sb.append("<! System=PowerForecast, Version=1.0, Code=UTF-8, Data=").append(batch.getReportDay()).append(" !>\n");
|
|
|
+// sb.append('<').append(marker).append("::").append(batch.getStationName()).append(">\n");
|
|
|
+// sb.append("Date=").append(LocalDate.parse(String.valueOf(batch.getReportDay()), FMT_REPORT_DAY).format(FMT_DATE))
|
|
|
+// .append(", Time=").append(batch.getEstReportTime().replace(":", "-")).append('\n');
|
|
|
+// sb.append("# 点号\t时间\t预测功率(MW)\t预计开机容量(MW)\t备注\n");
|
|
|
+// String capacityMw = String.format(Locale.ROOT, "%.2f", capacity / 1000.0);
|
|
|
+// for (int i = 0; i < points.size(); i++)
|
|
|
+// {
|
|
|
+// ReportPoint p = points.get(i);
|
|
|
+// sb.append(i + 1).append('\t')
|
|
|
+// .append(FMT_POINT_TIME.format(Instant.ofEpochSecond(p.forecastTime))).append('\t')
|
|
|
+// .append(String.format(Locale.ROOT, "%.2f", p.power / 1000.0)).append('\t')
|
|
|
+// .append(capacityMw).append('\t')
|
|
|
+// .append("正常").append('\n');
|
|
|
+// }
|
|
|
+// sb.append("</").append(marker).append("::").append(batch.getStationName()).append(">\n");
|
|
|
+// Files.write(target.toPath(), sb.toString().getBytes(StandardCharsets.UTF_8));
|
|
|
+// return target;
|
|
|
+// }
|
|
|
+
|
|
|
+// /**
|
|
|
+// * 按批次号加载上报数据点, 按预测时刻升序(power 为 kW 原始值)
|
|
|
+// */
|
|
|
+// private List<ReportPoint> loadReportPoints(DataPowerForecastReportBatch batch)
|
|
|
+// {
|
|
|
+// List<ReportPoint> points = new ArrayList<>();
|
|
|
+// if (DataPowerForecastReportBatch.TYPE_ULTRA.equals(batch.getType()))
|
|
|
+// {
|
|
|
+// DataSuperShortTermForecastReport q = new DataSuperShortTermForecastReport();
|
|
|
+// q.setBatchNo(batch.getBatchNo());
|
|
|
+// for (DataSuperShortTermForecastReport r : superShortTermReportMapper.selectDataSuperShortTermForecastReportList(q))
|
|
|
+// {
|
|
|
+// if (r.getForecastTime() != null && StringUtils.isNotBlank(r.getPower()))
|
|
|
+// {
|
|
|
+// points.add(new ReportPoint(r.getForecastTime(), Double.parseDouble(r.getPower())));
|
|
|
+// }
|
|
|
+// }
|
|
|
+// }
|
|
|
+// else
|
|
|
+// {
|
|
|
+// DataShortTermPowerForecastReport q = new DataShortTermPowerForecastReport();
|
|
|
+// q.setBatchNo(batch.getBatchNo());
|
|
|
+// for (DataShortTermPowerForecastReport r : shortTermReportMapper.selectDataShortTermPowerForecastReportList(q))
|
|
|
+// {
|
|
|
+// if (r.getForecastTime() != null && StringUtils.isNotBlank(r.getPower()))
|
|
|
+// {
|
|
|
+// points.add(new ReportPoint(r.getForecastTime(), Double.parseDouble(r.getPower())));
|
|
|
+// }
|
|
|
+// }
|
|
|
+// }
|
|
|
+// points.sort(Comparator.comparingLong(p -> p.forecastTime));
|
|
|
+// return points;
|
|
|
+// }
|
|
|
+
|
|
|
+// /**
|
|
|
+// * 上报数据点: 预测时刻(UTC秒) + 功率(kW)
|
|
|
+// */
|
|
|
+// private static class ReportPoint
|
|
|
+// {
|
|
|
+// private final long forecastTime;
|
|
|
+
|
|
|
+// private final double power;
|
|
|
+
|
|
|
+// ReportPoint(long forecastTime, double power)
|
|
|
+// {
|
|
|
+// this.forecastTime = forecastTime;
|
|
|
+// this.power = power;
|
|
|
+// }
|
|
|
+// }
|
|
|
+
|
|
|
+// /**
|
|
|
+// * 读取字典配置, 解析为场站配置列表
|
|
|
+// */
|
|
|
+// private List<Config> loadConfigs()
|
|
|
+// {
|
|
|
+// try
|
|
|
+// {
|
|
|
+// List<SysDictData> dictList = dictTypeService.selectDictDataByType(DICT_TYPE);
|
|
|
+// if (dictList == null || dictList.isEmpty())
|
|
|
+// {
|
|
|
+// return Collections.emptyList();
|
|
|
+// }
|
|
|
+// String dictValue = dictList.get(0).getDictValue();
|
|
|
+// if (StringUtils.isBlank(dictValue))
|
|
|
+// {
|
|
|
+// return Collections.emptyList();
|
|
|
+// }
|
|
|
+// List<Config> configs = JSON.parseArray(dictValue, Config.class);
|
|
|
+// return configs == null ? Collections.<Config>emptyList() : configs;
|
|
|
+// }
|
|
|
+// catch (Exception e)
|
|
|
+// {
|
|
|
+// log.error("[PowerForecastReportBatch] 解析字典 {} 配置失败", DICT_TYPE, e);
|
|
|
+// return Collections.emptyList();
|
|
|
+// }
|
|
|
+// }
|
|
|
+
|
|
|
+// /**
|
|
|
+// * 处理单个场站配置: 遍历预计上报时点(升序), 在提前窗口内生成批次行并触发初始化
|
|
|
+// */
|
|
|
+// private void process(Config config)
|
|
|
+// {
|
|
|
+// if (config == null || StringUtils.isBlank(config.getStationCode()))
|
|
|
+// {
|
|
|
+// return;
|
|
|
+// }
|
|
|
+// if (!"daily".equals(config.getPeriod()))
|
|
|
+// {
|
|
|
+// log.warn("[PowerForecastReportBatch] period 非 daily, 跳过, stationCode={}", config.getStationCode());
|
|
|
+// return;
|
|
|
+// }
|
|
|
+// if (!DataPowerForecastReportBatch.TYPE_SHORT.equals(config.getType())
|
|
|
+// && !DataPowerForecastReportBatch.TYPE_ULTRA.equals(config.getType()))
|
|
|
+// {
|
|
|
+// log.warn("[PowerForecastReportBatch] type 未知, 跳过, stationCode={}, type={}",
|
|
|
+// config.getStationCode(), config.getType());
|
|
|
+// return;
|
|
|
+// }
|
|
|
+// ConfigStation q = new ConfigStation();
|
|
|
+// q.setStationCode(config.getStationCode());
|
|
|
+// List<ConfigStation> stations = configStationService.selectConfigStationList(q);
|
|
|
+// if (stations == null || stations.isEmpty())
|
|
|
+// {
|
|
|
+// log.warn("[PowerForecastReportBatch] 未找到场站, 跳过, stationCode={}", config.getStationCode());
|
|
|
+// return;
|
|
|
+// }
|
|
|
+// String stationName = stations.get(0).getStationName();
|
|
|
+// List<String> times = config.getTimes();
|
|
|
+// if (times == null || times.isEmpty())
|
|
|
+// {
|
|
|
+// log.warn("[PowerForecastReportBatch] times 为空, 跳过, stationCode={}", config.getStationCode());
|
|
|
+// return;
|
|
|
+// }
|
|
|
+// times.sort(Comparator.naturalOrder());
|
|
|
+// for (String t : times)
|
|
|
+// {
|
|
|
+// LocalTime slotTime;
|
|
|
+// try
|
|
|
+// {
|
|
|
+// slotTime = LocalTime.parse(t);
|
|
|
+// }
|
|
|
+// catch (Exception e)
|
|
|
+// {
|
|
|
+// log.warn("[PowerForecastReportBatch] 时点格式非法, 跳过, stationCode={}, time={}",
|
|
|
+// config.getStationCode(), t);
|
|
|
+// continue;
|
|
|
+// }
|
|
|
+// LocalDateTime now = LocalDateTime.now(ZONE_SH);
|
|
|
+// LocalDate today = LocalDate.now(ZONE_SH);
|
|
|
+// LocalDateTime slot = today.atTime(slotTime);
|
|
|
+// // 已过时点, 跳过后续更远的时点
|
|
|
+// if (now.isAfter(slot))
|
|
|
+// {
|
|
|
+// continue;
|
|
|
+// }
|
|
|
+// // 未到提前窗口, 后续时点更远, 直接结束
|
|
|
+// if (now.isBefore(slot.minusMinutes(config.getInitInterval() == null ? 0 : config.getInitInterval())))
|
|
|
+// {
|
|
|
+// break;
|
|
|
+// }
|
|
|
+// int reportDay = Integer.parseInt(today.format(FMT_REPORT_DAY));
|
|
|
+// boolean exists = reportBatchService.selectByTypeDayTime(config.getType(), reportDay, t)
|
|
|
+// .stream().anyMatch(b -> config.getStationCode().equals(b.getStationCode()));
|
|
|
+// if (exists)
|
|
|
+// {
|
|
|
+// continue;
|
|
|
+// }
|
|
|
+// DataPowerForecastReportBatch b = new DataPowerForecastReportBatch();
|
|
|
+// b.setStationCode(config.getStationCode());
|
|
|
+// b.setStationName(stationName);
|
|
|
+// b.setType(config.getType());
|
|
|
+// b.setReportDay(reportDay);
|
|
|
+// b.setEstReportTime(t);
|
|
|
+// b.setStatus(DataPowerForecastReportBatch.STATUS_PENDING);
|
|
|
+// b.setGenerateSource("auto");
|
|
|
+// b.setBatchNo(prefix(config.getType()) + slot.format(FMT_BATCH_NO) + "_" + config.getStationCode());
|
|
|
+// reportBatchService.insertDataPowerForecastReportBatch(b);
|
|
|
+// log.info("[PowerForecastReportBatch] 新生成上报批次, batchNo={}, stationCode={}, time={}",
|
|
|
+// b.getBatchNo(), config.getStationCode(), t);
|
|
|
+// factory.getInstant(config.getType()).initData(reportDay, t);
|
|
|
+// }
|
|
|
+// }
|
|
|
+
|
|
|
+// /**
|
|
|
+// * 批次号前缀: 超短期 ULT, 其余 ST
|
|
|
+// */
|
|
|
+// private static String prefix(String type)
|
|
|
+// {
|
|
|
+// return "ultra".equals(type) ? "ULT" : "ST";
|
|
|
+// }
|
|
|
+
|
|
|
+// /**
|
|
|
+// * 字典 power_forecast_report_batch_config 的单个场站配置
|
|
|
+// */
|
|
|
+// public static class Config
|
|
|
+// {
|
|
|
+// /** 场站编码 */
|
|
|
+// private String stationCode;
|
|
|
+
|
|
|
+// /** 类型(short短期,ultra超短期) */
|
|
|
+// private String type;
|
|
|
+
|
|
|
+// /** 周期(daily) */
|
|
|
+// private String period;
|
|
|
+
|
|
|
+// /** 预计上报时点列表(HH:mm:ss) */
|
|
|
+// private List<String> times;
|
|
|
+
|
|
|
+// /** 提前初始化窗口(分钟), 缺省 0 */
|
|
|
+// private Integer initInterval;
|
|
|
+
|
|
|
+// public String getStationCode()
|
|
|
+// {
|
|
|
+// return stationCode;
|
|
|
+// }
|
|
|
+
|
|
|
+// public void setStationCode(String stationCode)
|
|
|
+// {
|
|
|
+// this.stationCode = stationCode;
|
|
|
+// }
|
|
|
+
|
|
|
+// public String getType()
|
|
|
+// {
|
|
|
+// return type;
|
|
|
+// }
|
|
|
+
|
|
|
+// public void setType(String type)
|
|
|
+// {
|
|
|
+// this.type = type;
|
|
|
+// }
|
|
|
+
|
|
|
+// public String getPeriod()
|
|
|
+// {
|
|
|
+// return period;
|
|
|
+// }
|
|
|
+
|
|
|
+// public void setPeriod(String period)
|
|
|
+// {
|
|
|
+// this.period = period;
|
|
|
+// }
|
|
|
+
|
|
|
+// public List<String> getTimes()
|
|
|
+// {
|
|
|
+// return times;
|
|
|
+// }
|
|
|
+
|
|
|
+// public void setTimes(List<String> times)
|
|
|
+// {
|
|
|
+// this.times = times;
|
|
|
+// }
|
|
|
+
|
|
|
+// public Integer getInitInterval()
|
|
|
+// {
|
|
|
+// return initInterval;
|
|
|
+// }
|
|
|
+
|
|
|
+// public void setInitInterval(Integer initInterval)
|
|
|
+// {
|
|
|
+// this.initInterval = initInterval;
|
|
|
+// }
|
|
|
+// }
|
|
|
+// }
|