|
|
@@ -0,0 +1,277 @@
|
|
|
+package com.ufo.project.forecast.shortterm.power.controller;
|
|
|
+
|
|
|
+import java.io.IOException;
|
|
|
+import java.math.BigDecimal;
|
|
|
+import java.math.RoundingMode;
|
|
|
+import java.net.URLEncoder;
|
|
|
+import java.text.SimpleDateFormat;
|
|
|
+import java.util.ArrayList;
|
|
|
+import java.util.Calendar;
|
|
|
+import java.util.Comparator;
|
|
|
+import java.util.Date;
|
|
|
+import java.util.HashMap;
|
|
|
+import java.util.List;
|
|
|
+import java.util.Map;
|
|
|
+import java.util.TreeMap;
|
|
|
+import java.util.TreeSet;
|
|
|
+import javax.servlet.http.HttpServletResponse;
|
|
|
+import org.slf4j.Logger;
|
|
|
+import org.slf4j.LoggerFactory;
|
|
|
+import org.springframework.beans.factory.annotation.Autowired;
|
|
|
+import org.springframework.security.access.prepost.PreAuthorize;
|
|
|
+import org.springframework.web.bind.annotation.GetMapping;
|
|
|
+import org.springframework.web.bind.annotation.RequestMapping;
|
|
|
+import org.springframework.web.bind.annotation.RequestParam;
|
|
|
+import org.springframework.web.bind.annotation.RestController;
|
|
|
+import com.alibaba.excel.EasyExcel;
|
|
|
+import com.ufo.base.common.utils.StringUtils;
|
|
|
+import com.ufo.base.framework.aspectj.lang.annotation.Log;
|
|
|
+import com.ufo.base.framework.aspectj.lang.enums.BusinessType;
|
|
|
+import com.ufo.base.framework.web.controller.BaseController;
|
|
|
+import com.ufo.base.framework.web.domain.AjaxResult;
|
|
|
+import com.ufo.project.forecast.shortterm.power.domain.UltraShortTermPowerForecastCsvRow;
|
|
|
+import com.ufo.project.forecast.shortterm.power.domain.UltraShortTermPowerForecastData;
|
|
|
+import com.ufo.project.forecast.shortterm.power.domain.UltraShortTermPowerSingleExport;
|
|
|
+import com.ufo.project.forecast.shortterm.power.util.ExcelForecastFileUtil;
|
|
|
+import com.ufo.project.model.domain.DataElectricityLocal;
|
|
|
+import com.ufo.project.model.domain.ModelPredictionTasks;
|
|
|
+import com.ufo.project.model.service.IDataElectricityLocalService;
|
|
|
+import com.ufo.project.model.service.IModelPredictionTasksService;
|
|
|
+
|
|
|
+/**
|
|
|
+ * 超短期功率预测Controller
|
|
|
+ *
|
|
|
+ * @author ufo
|
|
|
+ */
|
|
|
+@RestController
|
|
|
+@RequestMapping("/power/ultraShortTermPowerForecasting")
|
|
|
+public class UltraShortTermPowerForecastingController extends BaseController
|
|
|
+{
|
|
|
+ private static final Logger log = LoggerFactory.getLogger(UltraShortTermPowerForecastingController.class);
|
|
|
+
|
|
|
+ private static final String PATTERN_SECOND = "yyyy-MM-dd HH:mm:ss";
|
|
|
+ private static final String PATTERN_MINUTE = "yyyy-MM-dd HH:mm";
|
|
|
+ private static final String PATTERN_COMPACT = "yyyyMMddHHmm";
|
|
|
+
|
|
|
+ @Autowired
|
|
|
+ private IModelPredictionTasksService modelPredictionTasksService;
|
|
|
+
|
|
|
+ @Autowired
|
|
|
+ private IDataElectricityLocalService dataElectricityLocalService;
|
|
|
+
|
|
|
+ /**
|
|
|
+ * 获取超短期功率预测数据(预测 + 实发功率合并)
|
|
|
+ *
|
|
|
+ * @param stationId 场站id
|
|
|
+ * @param startTime 开始时间 yyyy-MM-dd HH:mm:ss
|
|
|
+ * @param endTime 截止时间 yyyy-MM-dd HH:mm:ss
|
|
|
+ */
|
|
|
+ @PreAuthorize("@ss.hasPermi('electricity:forecast:ultrashorttermpower')")
|
|
|
+ @GetMapping("/report")
|
|
|
+ public AjaxResult report(@RequestParam("stationId") Long stationId,
|
|
|
+ @RequestParam("startTime") String startTime, @RequestParam("endTime") String endTime)
|
|
|
+ {
|
|
|
+ return success(queryForecastData(stationId, startTime, endTime));
|
|
|
+ }
|
|
|
+
|
|
|
+ /**
|
|
|
+ * 导出超短期功率预测数据
|
|
|
+ *
|
|
|
+ * @param stationId 场站id
|
|
|
+ * @param startTime 开始时间 yyyy-MM-dd HH:mm:ss
|
|
|
+ * @param endTime 截止时间 yyyy-MM-dd HH:mm:ss
|
|
|
+ * @param type 0 单点预测; 1 单次预测
|
|
|
+ */
|
|
|
+ @PreAuthorize("@ss.hasPermi('electricity:forecast:ultrashorttermpower')")
|
|
|
+ @Log(title = "超短期功率预测", businessType = BusinessType.EXPORT)
|
|
|
+ @GetMapping("/export")
|
|
|
+ public void export(HttpServletResponse response,
|
|
|
+ @RequestParam("stationId") Long stationId,
|
|
|
+ @RequestParam("startTime") String startTime, @RequestParam("endTime") String endTime,
|
|
|
+ @RequestParam(value = "type", defaultValue = "0") Integer type) throws IOException
|
|
|
+ {
|
|
|
+ List<UltraShortTermPowerForecastData> data = queryForecastData(stationId, startTime, endTime);
|
|
|
+ response.setContentType("application/vnd.openxmlformats-officedocument.spreadsheetml.sheet");
|
|
|
+ response.setCharacterEncoding("utf-8");
|
|
|
+ String fileName = URLEncoder.encode(buildFileName(startTime, endTime), "UTF-8").replaceAll("\\+", "%20");
|
|
|
+ response.setHeader("Content-Disposition", "attachment;filename*=utf-8''" + fileName);
|
|
|
+ if (type != null && type == 1)
|
|
|
+ {
|
|
|
+ List<UltraShortTermPowerSingleExport> rows = new ArrayList<>();
|
|
|
+ for (UltraShortTermPowerForecastData item : data)
|
|
|
+ {
|
|
|
+ UltraShortTermPowerSingleExport row = new UltraShortTermPowerSingleExport();
|
|
|
+ row.setTime(item.getTime());
|
|
|
+ row.setMonitoredPower(item.getMonitoredPower());
|
|
|
+ row.setPower(item.getPower());
|
|
|
+ row.setBias(item.getBias());
|
|
|
+ rows.add(row);
|
|
|
+ }
|
|
|
+ EasyExcel.write(response.getOutputStream(), UltraShortTermPowerSingleExport.class)
|
|
|
+ .sheet("超短期功率预测").doWrite(rows);
|
|
|
+ }
|
|
|
+ else
|
|
|
+ {
|
|
|
+ EasyExcel.write(response.getOutputStream(), UltraShortTermPowerForecastData.class)
|
|
|
+ .sheet("超短期功率预测").doWrite(data);
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ /**
|
|
|
+ * 查询预测任务并解析 result_path 对应文件,与实发功率按时间 merge
|
|
|
+ */
|
|
|
+ private List<UltraShortTermPowerForecastData> queryForecastData(Long stationId, String startTimeStr, String endTimeStr)
|
|
|
+ {
|
|
|
+ List<UltraShortTermPowerForecastData> result = new ArrayList<>();
|
|
|
+ try
|
|
|
+ {
|
|
|
+ SimpleDateFormat sdf = new SimpleDateFormat(PATTERN_SECOND);
|
|
|
+ Date startTime = sdf.parse(startTimeStr);
|
|
|
+ Date endTime = sdf.parse(endTimeStr);
|
|
|
+
|
|
|
+ // 逻辑#1 预测数据: target_time 在 [startTime当日0点, endTime当日23:59:59] 区间
|
|
|
+ Date queryStart = startOfDay(startTime);
|
|
|
+ Date queryEnd = endOfDay(endTime);
|
|
|
+ List<ModelPredictionTasks> tasks = modelPredictionTasksService
|
|
|
+ .selectPredictionTasks(stationId, "ultra_short", queryStart, queryEnd);
|
|
|
+ Map<String, UltraShortTermPowerForecastData> forecastMap = new TreeMap<>();
|
|
|
+ for (ModelPredictionTasks task : tasks)
|
|
|
+ {
|
|
|
+ List<UltraShortTermPowerForecastCsvRow> rows = ExcelForecastFileUtil.readResultFile(
|
|
|
+ task.getResultPath(), UltraShortTermPowerForecastCsvRow.class);
|
|
|
+ if (rows == null)
|
|
|
+ {
|
|
|
+ continue;
|
|
|
+ }
|
|
|
+ for (UltraShortTermPowerForecastCsvRow row : rows)
|
|
|
+ {
|
|
|
+ String time = ExcelForecastFileUtil.formatTime(row.getTime());
|
|
|
+ if (StringUtils.isEmpty(time) || !inRange(time, startTime, endTime))
|
|
|
+ {
|
|
|
+ continue;
|
|
|
+ }
|
|
|
+ forecastMap.put(time, toData(row));
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ // 逻辑#2 实发功率
|
|
|
+ List<DataElectricityLocal> actualList = dataElectricityLocalService
|
|
|
+ .selectActualPowerList(stationId, startTime, endTime);
|
|
|
+ Map<String, Double> actualMap = new HashMap<>();
|
|
|
+ for (DataElectricityLocal actual : actualList)
|
|
|
+ {
|
|
|
+ actualMap.put(formatDate(actual.getTm(), PATTERN_MINUTE), actual.getActualPower());
|
|
|
+ }
|
|
|
+
|
|
|
+ // merge:两边时间并集,缺失补 0
|
|
|
+ TreeSet<String> keys = new TreeSet<>(forecastMap.keySet());
|
|
|
+ keys.addAll(actualMap.keySet());
|
|
|
+ for (String key : keys)
|
|
|
+ {
|
|
|
+ UltraShortTermPowerForecastData data = forecastMap.get(key);
|
|
|
+ if (data == null)
|
|
|
+ {
|
|
|
+ data = new UltraShortTermPowerForecastData();
|
|
|
+ data.setTime(key);
|
|
|
+ }
|
|
|
+ Double monitored = actualMap.get(key);
|
|
|
+ data.setMonitoredPower(monitored == null ? 0D : monitored);
|
|
|
+ double power = data.getPower() == null ? 0D : data.getPower();
|
|
|
+ data.setBias(round2(data.getMonitoredPower() - power));
|
|
|
+ result.add(data);
|
|
|
+ }
|
|
|
+ result.sort(Comparator.comparing(UltraShortTermPowerForecastData::getTime));
|
|
|
+ }
|
|
|
+ catch (Exception e)
|
|
|
+ {
|
|
|
+ log.error("超短期功率预测数据查询失败: stationId={}, startTime={}, endTime={}",
|
|
|
+ stationId, startTimeStr, endTimeStr, e);
|
|
|
+ }
|
|
|
+ return result;
|
|
|
+ }
|
|
|
+
|
|
|
+ private UltraShortTermPowerForecastData toData(UltraShortTermPowerForecastCsvRow row)
|
|
|
+ {
|
|
|
+ UltraShortTermPowerForecastData data = new UltraShortTermPowerForecastData();
|
|
|
+ data.setTime(ExcelForecastFileUtil.formatTime(row.getTime()));
|
|
|
+ data.setPower(row.getPower());
|
|
|
+ data.setPower15(row.getPower15());
|
|
|
+ data.setPower30(row.getPower30());
|
|
|
+ data.setPower45(row.getPower45());
|
|
|
+ data.setPower60(row.getPower60());
|
|
|
+ data.setPower75(row.getPower75());
|
|
|
+ data.setPower90(row.getPower90());
|
|
|
+ data.setPower105(row.getPower105());
|
|
|
+ data.setPower120(row.getPower120());
|
|
|
+ data.setPower135(row.getPower135());
|
|
|
+ data.setPower150(row.getPower150());
|
|
|
+ data.setPower165(row.getPower165());
|
|
|
+ data.setPower180(row.getPower180());
|
|
|
+ data.setPower195(row.getPower195());
|
|
|
+ data.setPower210(row.getPower210());
|
|
|
+ data.setPower225(row.getPower225());
|
|
|
+ data.setPower240(row.getPower240());
|
|
|
+ return data;
|
|
|
+ }
|
|
|
+
|
|
|
+ /**
|
|
|
+ * 判断格式化时间(yyyy-MM-dd HH:mm)是否在 [startTime, endTime] 区间内(字符串比较,无需时区换算)
|
|
|
+ */
|
|
|
+ private boolean inRange(String timeKey, Date startTime, Date endTime)
|
|
|
+ {
|
|
|
+ return timeKey.compareTo(formatDate(startTime, PATTERN_MINUTE)) >= 0
|
|
|
+ && timeKey.compareTo(formatDate(endTime, PATTERN_MINUTE)) <= 0;
|
|
|
+ }
|
|
|
+
|
|
|
+ private String formatDate(Date date, String pattern)
|
|
|
+ {
|
|
|
+ return new SimpleDateFormat(pattern).format(date);
|
|
|
+ }
|
|
|
+
|
|
|
+ /**
|
|
|
+ * 取日期当天 0 点
|
|
|
+ */
|
|
|
+ private Date startOfDay(Date date)
|
|
|
+ {
|
|
|
+ Calendar cal = Calendar.getInstance();
|
|
|
+ cal.setTime(date);
|
|
|
+ cal.set(Calendar.HOUR_OF_DAY, 0);
|
|
|
+ cal.set(Calendar.MINUTE, 0);
|
|
|
+ cal.set(Calendar.SECOND, 0);
|
|
|
+ cal.set(Calendar.MILLISECOND, 0);
|
|
|
+ return cal.getTime();
|
|
|
+ }
|
|
|
+
|
|
|
+ /**
|
|
|
+ * 取日期当天 23:59:59
|
|
|
+ */
|
|
|
+ private Date endOfDay(Date date)
|
|
|
+ {
|
|
|
+ Calendar cal = Calendar.getInstance();
|
|
|
+ cal.setTime(date);
|
|
|
+ cal.set(Calendar.HOUR_OF_DAY, 23);
|
|
|
+ cal.set(Calendar.MINUTE, 59);
|
|
|
+ cal.set(Calendar.SECOND, 59);
|
|
|
+ cal.set(Calendar.MILLISECOND, 0);
|
|
|
+ return cal.getTime();
|
|
|
+ }
|
|
|
+
|
|
|
+ private double round2(double value)
|
|
|
+ {
|
|
|
+ return BigDecimal.valueOf(value).setScale(2, RoundingMode.HALF_UP).doubleValue();
|
|
|
+ }
|
|
|
+
|
|
|
+ private String buildFileName(String startTime, String endTime)
|
|
|
+ {
|
|
|
+ try
|
|
|
+ {
|
|
|
+ SimpleDateFormat sdf = new SimpleDateFormat(PATTERN_SECOND);
|
|
|
+ return "超短期预测-" + formatDate(sdf.parse(startTime), PATTERN_COMPACT)
|
|
|
+ + "-" + formatDate(sdf.parse(endTime), PATTERN_COMPACT) + ".xlsx";
|
|
|
+ }
|
|
|
+ catch (Exception e)
|
|
|
+ {
|
|
|
+ return "超短期预测.xlsx";
|
|
|
+ }
|
|
|
+ }
|
|
|
+}
|