3 Angajamente 96f6810007 ... 6941e19ff2

Autor SHA1 Permisiunea de a trimite mesaje. Dacă este dezactivată, utilizatorul nu va putea trimite nici un fel de mesaj Data
  xiaoguohua 6941e19ff2 Merge branch 'master' of http://36.141.74.62:4888/yeguanglin/forecast 1 lună în urmă
  xiaoguohua cfc6478bac 更新数据库 1 lună în urmă
  xiaoguohua 6727d78b41 同步数据库的修改 1 lună în urmă
21 a modificat fișierele cu 121 adăugiri și 2003 ștergeri
  1. 8 2
      doc/数据库脚本/gateway.sql
  2. 3 63
      forecast-backend-server/src/main/java/com/ufo/project/data/controller/DataController.java
  3. 0 68
      forecast-backend-server/src/main/java/com/ufo/project/data/domain/vo/ShortTermPowerForecastReportQuery.java
  4. 0 128
      forecast-backend-server/src/main/java/com/ufo/project/data/domain/vo/ShortTermPowerForecastReportVO.java
  5. 0 68
      forecast-backend-server/src/main/java/com/ufo/project/data/domain/vo/UltraShortTermPowerForecastReportQuery.java
  6. 0 129
      forecast-backend-server/src/main/java/com/ufo/project/data/domain/vo/UltraShortTermPowerForecastReportVO.java
  7. 0 22
      forecast-backend-server/src/main/java/com/ufo/project/data/service/IShortTermPowerForecastReportService.java
  8. 0 23
      forecast-backend-server/src/main/java/com/ufo/project/data/service/IUltraShortTermPowerForecastReportService.java
  9. 0 661
      forecast-backend-server/src/main/java/com/ufo/project/data/service/impl/ShortTermPowerForecastReportServiceImpl.java
  10. 0 780
      forecast-backend-server/src/main/java/com/ufo/project/data/service/impl/UltraShortTermPowerForecastReportServiceImpl.java
  11. 0 4
      forecast-backend-server/src/main/java/com/ufo/project/forecast/supershort/domain/DataUltraShortTermPowerForecasting.java
  12. 6 6
      forecast-backend-server/src/main/java/com/ufo/project/weather/domain/DataWeatherLocal.java
  13. 0 5
      forecast-backend-server/src/main/resources/mybatis/supershort/DataUltraShortTermPowerForecastingMapper.xml
  14. 6 6
      forecast-backend-server/src/main/resources/mybatis/weather/DataWeatherLocalMapper.xml
  15. 0 1
      forecast-backend-vue/src/components/layout/SideMenu.vue
  16. 28 6
      forecast-dao/src/main/java/cn/oleauto/config/domain/ConfigWeatherLocal.java
  17. 39 11
      forecast-dao/src/main/java/cn/oleauto/data/domain/DataWeatherLocal.java
  18. 15 6
      forecast-dao/src/main/resources/mapper/config/ConfigWeatherLocalMapper.xml
  19. 16 6
      forecast-dao/src/main/resources/mapper/data/DataWeatherLocalMapper.xml
  20. 0 2
      release_note/2026.09.03/20260903_dp.sql
  21. 0 6
      release_note/2026.09.17/20260917_dp.sql

+ 8 - 2
doc/数据库脚本/gateway.sql

@@ -278,9 +278,11 @@ CREATE TABLE IF NOT EXISTS config_weather_local
 (
     id BIGSERIAL PRIMARY KEY,
     config_station_id bigint NOT NULL,
-    horizontal_irradiance json,
+    irradiance json,
     inclined_irradiance json,
+    daily_irradiance json,
     temperature json,
+    board_temperature json,
     pressure json,
     humidity json,
     wind_speed json,
@@ -297,7 +299,7 @@ ON COLUMN config_weather_local.id IS '主键';
 COMMENT
 ON COLUMN config_weather_local.config_station_id IS '场站id';
 COMMENT
-ON COLUMN config_weather_local.horizontal_irradiance IS '水平面总辐照度测点配置
+ON COLUMN config_weather_local.irradiance IS '总辐照度测点配置
 {
 deviceId:xxx
 pointType:YC|YX|YM
@@ -306,8 +308,12 @@ pointCode:xxx
 COMMENT
 ON COLUMN config_weather_local.inclined_irradiance IS '斜面辐照度测点配置';
 COMMENT
+ON COLUMN config_weather_local.daily_irradiance IS '日辐射度累计值';
+COMMENT
 ON COLUMN config_weather_local.temperature IS '温度测点配置';
 COMMENT
+ON COLUMN config_weather_local.board_temperature IS '组件温度测点配置';
+COMMENT
 ON COLUMN config_weather_local.pressure IS '气压测点配置';
 COMMENT
 ON COLUMN config_weather_local.humidity IS '湿度测点配置';

+ 3 - 63
forecast-backend-server/src/main/java/com/ufo/project/data/controller/DataController.java

@@ -7,8 +7,10 @@ import java.util.ArrayList;
 import java.util.Collections;
 import java.util.Date;
 import java.util.HashMap;
+import java.util.HashSet;
 import java.util.List;
 import java.util.Map;
+import java.util.Set;
 import javax.servlet.http.HttpServletResponse;
 import org.springframework.beans.factory.annotation.Autowired;
 import org.springframework.security.access.prepost.PreAuthorize;
@@ -23,12 +25,6 @@ import com.ufo.base.framework.web.page.TableDataInfo;
 import com.ufo.base.common.utils.poi.ExcelUtil;
 import com.ufo.project.data.domain.IrradiancePowerComparisonQuery;
 import com.ufo.project.data.domain.vo.IrradiancePowerComparisonVO;
-import com.ufo.project.data.domain.vo.ShortTermPowerForecastReportQuery;
-import com.ufo.project.data.domain.vo.ShortTermPowerForecastReportVO;
-import com.ufo.project.data.domain.vo.UltraShortTermPowerForecastReportQuery;
-import com.ufo.project.data.domain.vo.UltraShortTermPowerForecastReportVO;
-import com.ufo.project.data.service.IShortTermPowerForecastReportService;
-import com.ufo.project.data.service.IUltraShortTermPowerForecastReportService;
 import com.ufo.project.forecast.shortterm.power.domain.DataShortTermPowerForecastIssued;
 import com.ufo.project.forecast.shortterm.power.service.IDataShortTermPowerForecastIssuedService;
 import com.ufo.project.forecast.shortterm.weather.domain.DataShortTermWeatherForecastIssued;
@@ -62,12 +58,6 @@ public class DataController extends BaseController
     @Autowired
     private IDataWeatherLocalService weatherLocalService;
 
-    @Autowired
-    private IShortTermPowerForecastReportService shortTermPowerForecastReportService;
-
-    @Autowired
-    private IUltraShortTermPowerForecastReportService ultraShortTermPowerForecastReportService;
-
     /**
      * 辐照度功率对比
      */
@@ -94,56 +84,6 @@ public class DataController extends BaseController
         util.exportExcel(response, list, "辐照度功率对比");
     }
 
-    /**
-     * 短期预测报表(日报、月报、年报)
-     */
-    @PreAuthorize("@ss.hasPermi('data:shortTermPowerForecastReport:list')")
-    @PostMapping("/shortTermPowerForecastReport")
-    public TableDataInfo shortTermPowerForecastReport(@RequestBody ShortTermPowerForecastReportQuery query)
-    {
-        List<ShortTermPowerForecastReportVO> list = shortTermPowerForecastReportService.selectReportList(query);
-        return getDataTable(list);
-    }
-
-    /**
-     * 短期预测报表导出
-     */
-    @PreAuthorize("@ss.hasPermi('data:shortTermPowerForecastReport:export')")
-    @Log(title = "短期预测报表", businessType = BusinessType.EXPORT)
-    @PostMapping("/shortTermPowerForecastReport/export")
-    public void shortTermPowerForecastReportExport(HttpServletResponse response,
-            @RequestBody ShortTermPowerForecastReportQuery query)
-    {
-        List<ShortTermPowerForecastReportVO> list = shortTermPowerForecastReportService.selectReportList(query);
-        ExcelUtil<ShortTermPowerForecastReportVO> util = new ExcelUtil<>(ShortTermPowerForecastReportVO.class);
-        util.exportExcel(response, list, "短期预测报表");
-    }
-
-    /**
-     * 超短期预测报表(日报、月报、年报)
-     */
-    @PreAuthorize("@ss.hasPermi('data:ultraShortTermPowerForecastReport:list')")
-    @PostMapping("/ultraShortTermPowerForecastReport")
-    public TableDataInfo ultraShortTermPowerForecastReport(@RequestBody UltraShortTermPowerForecastReportQuery query)
-    {
-        List<UltraShortTermPowerForecastReportVO> list = ultraShortTermPowerForecastReportService.selectReportList(query);
-        return getDataTable(list);
-    }
-
-    /**
-     * 超短期预测报表导出
-     */
-    @PreAuthorize("@ss.hasPermi('data:ultraShortTermPowerForecastReport:export')")
-    @Log(title = "超短期预测报表", businessType = BusinessType.EXPORT)
-    @PostMapping("/ultraShortTermPowerForecastReport/export")
-    public void ultraShortTermPowerForecastReportExport(HttpServletResponse response,
-            @RequestBody UltraShortTermPowerForecastReportQuery query)
-    {
-        List<UltraShortTermPowerForecastReportVO> list = ultraShortTermPowerForecastReportService.selectReportList(query);
-        ExcelUtil<UltraShortTermPowerForecastReportVO> util = new ExcelUtil<>(UltraShortTermPowerForecastReportVO.class);
-        util.exportExcel(response, list, "超短期预测报表");
-    }
-
     /**
      * 构建对比数据列表
      */
@@ -224,7 +164,7 @@ public class DataController extends BaseController
         {
             if (item.getTm() == null) continue;
             long ts = item.getTm().getTime();
-            dataMap.computeIfAbsent(ts, k -> new HashMap<>()).put("measuredIrradiance", item.getIrradiance());
+            dataMap.computeIfAbsent(ts, k -> new HashMap<>()).put("measuredIrradiance", item.getInclinedIrradiance());
         }
     }
 

+ 0 - 68
forecast-backend-server/src/main/java/com/ufo/project/data/domain/vo/ShortTermPowerForecastReportQuery.java

@@ -1,68 +0,0 @@
-package com.ufo.project.data.domain.vo;
-
-import javax.validation.constraints.NotBlank;
-
-/**
- * 短期预测报表查询参数
- *
- * @author ufo
- * @date 2026-09-07
- */
-public class ShortTermPowerForecastReportQuery
-{
-    /** 报表类型:daily-日报, monthly-月报, yearly-年报 */
-    @NotBlank(message = "报表类型不能为空")
-    private String type;
-
-    /** 站点/场站 id */
-    @NotBlank(message = "站点id不能为空")
-    private String entityId;
-
-    /** 开始时间 yyyy-MM-dd */
-    @NotBlank(message = "开始时间不能为空")
-    private String startTime;
-
-    /** 结束时间 yyyy-MM-dd */
-    @NotBlank(message = "结束时间不能为空")
-    private String endTime;
-
-    public String getType()
-    {
-        return type;
-    }
-
-    public void setType(String type)
-    {
-        this.type = type;
-    }
-
-    public String getEntityId()
-    {
-        return entityId;
-    }
-
-    public void setEntityId(String entityId)
-    {
-        this.entityId = entityId;
-    }
-
-    public String getStartTime()
-    {
-        return startTime;
-    }
-
-    public void setStartTime(String startTime)
-    {
-        this.startTime = startTime;
-    }
-
-    public String getEndTime()
-    {
-        return endTime;
-    }
-
-    public void setEndTime(String endTime)
-    {
-        this.endTime = endTime;
-    }
-}

+ 0 - 128
forecast-backend-server/src/main/java/com/ufo/project/data/domain/vo/ShortTermPowerForecastReportVO.java

@@ -1,128 +0,0 @@
-package com.ufo.project.data.domain.vo;
-
-import java.io.Serializable;
-import java.math.BigDecimal;
-import com.ufo.base.framework.aspectj.lang.annotation.Excel;
-
-/**
- * 短期预测报表视图对象
- *
- * @author ufo
- * @date 2026-09-07
- */
-public class ShortTermPowerForecastReportVO implements Serializable
-{
-    private static final long serialVersionUID = 1L;
-
-    /** 时间(日报: yyyy-MM-dd, 月报: yyyy-MM, 年报: yyyy) */
-    @Excel(name = "时间")
-    private String time;
-
-    /** 开机容量(MW) */
-    @Excel(name = "开机容量(MW)")
-    private BigDecimal operatingCapacity;
-
-    /** 实发功率(MW) */
-    @Excel(name = "实发功率(MW)")
-    private BigDecimal actualPower;
-
-    /** 预测功率(MW) */
-    @Excel(name = "预测功率(MW)")
-    private BigDecimal forecastPower;
-
-    /** 均方根差 */
-    @Excel(name = "均方根差")
-    private BigDecimal rootMeanSquareError;
-
-    /** 平均绝对误差 */
-    @Excel(name = "平均绝对误差")
-    private BigDecimal meanAbsoluteError;
-
-    /** 相关性系数 */
-    @Excel(name = "相关性系数")
-    private BigDecimal correlationCoefficientR;
-
-    /** 最大误差合格率 */
-    @Excel(name = "最大误差合格率")
-    private BigDecimal maximumErrorPassRate;
-
-    public String getTime()
-    {
-        return time;
-    }
-
-    public void setTime(String time)
-    {
-        this.time = time;
-    }
-
-    public BigDecimal getOperatingCapacity()
-    {
-        return operatingCapacity;
-    }
-
-    public void setOperatingCapacity(BigDecimal operatingCapacity)
-    {
-        this.operatingCapacity = operatingCapacity;
-    }
-
-    public BigDecimal getActualPower()
-    {
-        return actualPower;
-    }
-
-    public void setActualPower(BigDecimal actualPower)
-    {
-        this.actualPower = actualPower;
-    }
-
-    public BigDecimal getForecastPower()
-    {
-        return forecastPower;
-    }
-
-    public void setForecastPower(BigDecimal forecastPower)
-    {
-        this.forecastPower = forecastPower;
-    }
-
-    public BigDecimal getRootMeanSquareError()
-    {
-        return rootMeanSquareError;
-    }
-
-    public void setRootMeanSquareError(BigDecimal rootMeanSquareError)
-    {
-        this.rootMeanSquareError = rootMeanSquareError;
-    }
-
-    public BigDecimal getMeanAbsoluteError()
-    {
-        return meanAbsoluteError;
-    }
-
-    public void setMeanAbsoluteError(BigDecimal meanAbsoluteError)
-    {
-        this.meanAbsoluteError = meanAbsoluteError;
-    }
-
-    public BigDecimal getCorrelationCoefficientR()
-    {
-        return correlationCoefficientR;
-    }
-
-    public void setCorrelationCoefficientR(BigDecimal correlationCoefficientR)
-    {
-        this.correlationCoefficientR = correlationCoefficientR;
-    }
-
-    public BigDecimal getMaximumErrorPassRate()
-    {
-        return maximumErrorPassRate;
-    }
-
-    public void setMaximumErrorPassRate(BigDecimal maximumErrorPassRate)
-    {
-        this.maximumErrorPassRate = maximumErrorPassRate;
-    }
-}

+ 0 - 68
forecast-backend-server/src/main/java/com/ufo/project/data/domain/vo/UltraShortTermPowerForecastReportQuery.java

@@ -1,68 +0,0 @@
-package com.ufo.project.data.domain.vo;
-
-import javax.validation.constraints.NotBlank;
-
-/**
- * 超短期预测报表查询参数
- *
- * @author ufo
- * @date 2026-09-07
- */
-public class UltraShortTermPowerForecastReportQuery
-{
-    /** 报表类型:daily-日报, monthly-月报, yearly-年报 */
-    @NotBlank(message = "报表类型不能为空")
-    private String type;
-
-    /** 站点/场站 id */
-    @NotBlank(message = "站点id不能为空")
-    private String entityId;
-
-    /** 开始时间 yyyy-MM-dd */
-    @NotBlank(message = "开始时间不能为空")
-    private String startTime;
-
-    /** 结束时间 yyyy-MM-dd */
-    @NotBlank(message = "结束时间不能为空")
-    private String endTime;
-
-    public String getType()
-    {
-        return type;
-    }
-
-    public void setType(String type)
-    {
-        this.type = type;
-    }
-
-    public String getEntityId()
-    {
-        return entityId;
-    }
-
-    public void setEntityId(String entityId)
-    {
-        this.entityId = entityId;
-    }
-
-    public String getStartTime()
-    {
-        return startTime;
-    }
-
-    public void setStartTime(String startTime)
-    {
-        this.startTime = startTime;
-    }
-
-    public String getEndTime()
-    {
-        return endTime;
-    }
-
-    public void setEndTime(String endTime)
-    {
-        this.endTime = endTime;
-    }
-}

+ 0 - 129
forecast-backend-server/src/main/java/com/ufo/project/data/domain/vo/UltraShortTermPowerForecastReportVO.java

@@ -1,129 +0,0 @@
-package com.ufo.project.data.domain.vo;
-
-import java.io.Serializable;
-import java.math.BigDecimal;
-
-import com.ufo.base.framework.aspectj.lang.annotation.Excel;
-
-/**
- * 超短期预测报表视图对象
- *
- * @author ufo
- * @date 2026-09-07
- */
-public class UltraShortTermPowerForecastReportVO implements Serializable
-{
-    private static final long serialVersionUID = 1L;
-
-    /** 时间(日报: yyyy-MM-dd, 月报: yyyy-MM, 年报: yyyy) */
-    @Excel(name = "时间")
-    private String time;
-
-    /** 开机容量(MW) */
-    @Excel(name = "开机容量(MW)")
-    private BigDecimal operatingCapacity;
-
-    /** 实发功率(MW) */
-    @Excel(name = "实发功率(MW)")
-    private BigDecimal actualPower;
-
-    /** 预测功率(MW) */
-    @Excel(name = "预测功率(MW)")
-    private BigDecimal forecastPower;
-
-    /** 均方根差 */
-    @Excel(name = "均方根差")
-    private BigDecimal rootMeanSquareError;
-
-    /** 平均绝对误差 */
-    @Excel(name = "平均绝对误差")
-    private BigDecimal meanAbsoluteError;
-
-    /** 相关性系数 */
-    @Excel(name = "相关性系数")
-    private BigDecimal correlationCoefficientR;
-
-    /** 4小时前预测准确率 */
-    @Excel(name = "4小时前预测准确率")
-    private BigDecimal aheadForecastAccuracy4h;
-
-    public String getTime()
-    {
-        return time;
-    }
-
-    public void setTime(String time)
-    {
-        this.time = time;
-    }
-
-    public BigDecimal getOperatingCapacity()
-    {
-        return operatingCapacity;
-    }
-
-    public void setOperatingCapacity(BigDecimal operatingCapacity)
-    {
-        this.operatingCapacity = operatingCapacity;
-    }
-
-    public BigDecimal getActualPower()
-    {
-        return actualPower;
-    }
-
-    public void setActualPower(BigDecimal actualPower)
-    {
-        this.actualPower = actualPower;
-    }
-
-    public BigDecimal getForecastPower()
-    {
-        return forecastPower;
-    }
-
-    public void setForecastPower(BigDecimal forecastPower)
-    {
-        this.forecastPower = forecastPower;
-    }
-
-    public BigDecimal getRootMeanSquareError()
-    {
-        return rootMeanSquareError;
-    }
-
-    public void setRootMeanSquareError(BigDecimal rootMeanSquareError)
-    {
-        this.rootMeanSquareError = rootMeanSquareError;
-    }
-
-    public BigDecimal getMeanAbsoluteError()
-    {
-        return meanAbsoluteError;
-    }
-
-    public void setMeanAbsoluteError(BigDecimal meanAbsoluteError)
-    {
-        this.meanAbsoluteError = meanAbsoluteError;
-    }
-
-    public BigDecimal getCorrelationCoefficientR()
-    {
-        return correlationCoefficientR;
-    }
-
-    public void setCorrelationCoefficientR(BigDecimal correlationCoefficientR)
-    {
-        this.correlationCoefficientR = correlationCoefficientR;
-    }
-
-    public BigDecimal getAheadForecastAccuracy4h()
-    {
-        return aheadForecastAccuracy4h;
-    }
-
-    public void setAheadForecastAccuracy4h(BigDecimal aheadForecastAccuracy4h)
-    {
-        this.aheadForecastAccuracy4h = aheadForecastAccuracy4h;
-    }
-}

+ 0 - 22
forecast-backend-server/src/main/java/com/ufo/project/data/service/IShortTermPowerForecastReportService.java

@@ -1,22 +0,0 @@
-package com.ufo.project.data.service;
-
-import java.util.List;
-import com.ufo.project.data.domain.vo.ShortTermPowerForecastReportQuery;
-import com.ufo.project.data.domain.vo.ShortTermPowerForecastReportVO;
-
-/**
- * 短期预测报表Service接口
- *
- * @author ufo
- * @date 2026-09-07
- */
-public interface IShortTermPowerForecastReportService
-{
-    /**
-     * 查询短期预测报表数据
-     *
-     * @param query 查询参数
-     * @return 报表数据列表
-     */
-    List<ShortTermPowerForecastReportVO> selectReportList(ShortTermPowerForecastReportQuery query);
-}

+ 0 - 23
forecast-backend-server/src/main/java/com/ufo/project/data/service/IUltraShortTermPowerForecastReportService.java

@@ -1,23 +0,0 @@
-package com.ufo.project.data.service;
-
-import java.util.List;
-
-import com.ufo.project.data.domain.vo.UltraShortTermPowerForecastReportQuery;
-import com.ufo.project.data.domain.vo.UltraShortTermPowerForecastReportVO;
-
-/**
- * 超短期预测报表Service接口
- *
- * @author ufo
- * @date 2026-09-07
- */
-public interface IUltraShortTermPowerForecastReportService
-{
-    /**
-     * 查询超短期预测报表列表
-     *
-     * @param query 查询参数
-     * @return 报表列表
-     */
-    List<UltraShortTermPowerForecastReportVO> selectReportList(UltraShortTermPowerForecastReportQuery query);
-}

+ 0 - 661
forecast-backend-server/src/main/java/com/ufo/project/data/service/impl/ShortTermPowerForecastReportServiceImpl.java

@@ -1,661 +0,0 @@
-package com.ufo.project.data.service.impl;
-
-import java.math.BigDecimal;
-import java.math.RoundingMode;
-import java.time.LocalDate;
-import java.time.YearMonth;
-import java.time.ZoneId;
-import java.time.format.DateTimeFormatter;
-import java.util.ArrayList;
-import java.util.Collections;
-import java.util.LinkedHashMap;
-import java.util.List;
-import java.util.Map;
-import java.util.Map.Entry;
-import java.util.stream.Collectors;
-import javax.annotation.PostConstruct;
-import org.springframework.beans.factory.annotation.Autowired;
-import org.springframework.stereotype.Service;
-import com.ufo.base.common.constant.CacheConstants;
-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.data.domain.vo.ShortTermPowerForecastReportQuery;
-import com.ufo.project.data.domain.vo.ShortTermPowerForecastReportVO;
-import com.ufo.project.data.service.IShortTermPowerForecastReportService;
-import com.ufo.project.forecast.shortterm.power.domain.DataShortTermPowerForecastIssued;
-import com.ufo.project.forecast.shortterm.power.service.IDataShortTermPowerForecastIssuedService;
-import com.ufo.project.model.domain.DataElectricityLocal;
-import com.ufo.project.model.service.IDataElectricityLocalService;
-
-/**
- * 短期预测报表Service业务层处理
- *
- * @author ufo
- * @date 2026-09-07
- */
-@Service
-public class ShortTermPowerForecastReportServiceImpl implements IShortTermPowerForecastReportService
-{
-    private static final int SCALE = 4;
-
-    /** Dict类型:短期预测误差阈值 */
-    private static final String DICT_TYPE_SHORT_TERM_ERROR_THRESHOLD = "short_term_error_threshold";
-
-    private static final DateTimeFormatter DATE_FMT = DateTimeFormatter.ofPattern("yyyy-MM-dd");
-    private static final DateTimeFormatter MONTH_FMT = DateTimeFormatter.ofPattern("yyyy-MM");
-    private static final DateTimeFormatter YEAR_FMT = DateTimeFormatter.ofPattern("yyyy");
-
-    private static final ZoneId ZONE_SHANGHAI = ZoneId.of("Asia/Shanghai");
-
-    private String errorThreshold;
-
-    @Autowired
-    private IDataElectricityLocalService electricityLocalService;
-
-    @Autowired
-    private IDataShortTermPowerForecastIssuedService powerForecastIssuedService;
-
-    @Autowired
-    private ISysDictTypeService dictTypeService;
-
-    /**
-     * 初始化阈值配置
-     */
-    @PostConstruct
-    public void init()
-    {
-        refreshErrorThreshold();
-    }
-
-    @Override
-    public List<ShortTermPowerForecastReportVO> selectReportList(ShortTermPowerForecastReportQuery query)
-    {
-        String type = query.getType();
-        String entityId = query.getEntityId();
-        String startTime = query.getStartTime();
-        String endTime = query.getEndTime();
-
-        // 1. 获取实发功率数据
-        List<DataElectricityLocal> actualList = electricityLocalService.selectActualPowerList(
-                parseLong(entityId), startTime, endTime);
-        if (actualList == null || actualList.isEmpty())
-        {
-            return Collections.emptyList();
-        }
-
-        // 2. 获取预测功率数据
-        List<DataShortTermPowerForecastIssued> forecastList = powerForecastIssuedService.selectByTimeRange(
-                entityId, parseLong(startTime), parseLong(endTime));
-
-        // 3. 按基准类型分组
-        switch (type)
-        {
-            case "daily":
-                return buildDailyReport(actualList, forecastList);
-            case "monthly":
-                return buildMonthlyReport(actualList, forecastList);
-            case "yearly":
-                return buildYearlyReport(actualList, forecastList);
-            default:
-                return Collections.emptyList();
-        }
-    }
-
-    /**
-     * 构建日报
-     */
-    private List<ShortTermPowerForecastReportVO> buildDailyReport(List<DataElectricityLocal> actualList,
-            List<DataShortTermPowerForecastIssued> forecastList)
-    {
-        Map<String, List<DataElectricityLocal>> dailyMap = groupByDay(actualList);
-        Map<String, List<DataShortTermPowerForecastIssued>> forecastDailyMap = groupForecastByDay(forecastList);
-
-        List<ShortTermPowerForecastReportVO> result = new ArrayList<>();
-        for (Entry<String, List<DataElectricityLocal>> entry : dailyMap.entrySet())
-        {
-            String day = entry.getKey();
-            List<DataElectricityLocal> records = entry.getValue();
-            List<DataShortTermPowerForecastIssued> forecastRecords = forecastDailyMap.getOrDefault(day, Collections.emptyList());
-
-            ShortTermPowerForecastReportVO vo = new ShortTermPowerForecastReportVO();
-            vo.setTime(day);
-            computeDailyMetrics(vo, records, forecastRecords);
-            result.add(vo);
-        }
-        return result;
-    }
-
-    /**
-     * 构建月报
-     */
-    private List<ShortTermPowerForecastReportVO> buildMonthlyReport(List<DataElectricityLocal> actualList,
-            List<DataShortTermPowerForecastIssued> forecastList)
-    {
-        Map<String, List<DataElectricityLocal>> monthlyMap = groupByMonth(actualList);
-        Map<String, List<DataShortTermPowerForecastIssued>> forecastMonthlyMap = groupForecastByMonth(forecastList);
-
-        List<ShortTermPowerForecastReportVO> result = new ArrayList<>();
-        for (Entry<String, List<DataElectricityLocal>> entry : monthlyMap.entrySet())
-        {
-            String month = entry.getKey();
-            List<DataElectricityLocal> records = entry.getValue();
-            List<DataShortTermPowerForecastIssued> forecastRecords =
-                    forecastMonthlyMap.getOrDefault(month, Collections.emptyList());
-
-            ShortTermPowerForecastReportVO vo = new ShortTermPowerForecastReportVO();
-            vo.setTime(month);
-            computeDailyMetrics(vo, records, forecastRecords);
-            result.add(vo);
-        }
-        return result;
-    }
-
-    /**
-     * 构建年报
-     */
-    private List<ShortTermPowerForecastReportVO> buildYearlyReport(List<DataElectricityLocal> actualList,
-            List<DataShortTermPowerForecastIssued> forecastList)
-    {
-        Map<String, List<DataElectricityLocal>> yearlyMap = groupByYear(actualList);
-        Map<String, List<DataShortTermPowerForecastIssued>> forecastYearlyMap = groupForecastByYear(forecastList);
-
-        List<ShortTermPowerForecastReportVO> result = new ArrayList<>();
-        for (Entry<String, List<DataElectricityLocal>> entry : yearlyMap.entrySet())
-        {
-            String year = entry.getKey();
-            List<DataElectricityLocal> records = entry.getValue();
-            List<DataShortTermPowerForecastIssued> forecastRecords =
-                    forecastYearlyMap.getOrDefault(year, Collections.emptyList());
-
-            ShortTermPowerForecastReportVO vo = new ShortTermPowerForecastReportVO();
-            vo.setTime(year);
-            computeDailyMetrics(vo, records, forecastRecords);
-            result.add(vo);
-        }
-        return result;
-    }
-
-    /**
-     * 计算指标(日报/月报/年报通用)
-     */
-    private void computeDailyMetrics(ShortTermPowerForecastReportVO vo,
-            List<DataElectricityLocal> actualRecords, List<DataShortTermPowerForecastIssued> forecastRecords)
-    {
-        // 1. operatingCapacity: 筛选 device_status = 0 AND grid_status = 1, MAX(actual_power) / 1000
-        BigDecimal operatingCapacity = computeOperatingCapacity(actualRecords);
-        vo.setOperatingCapacity(operatingCapacity);
-
-        // 2. actualPower: 筛选 grid_status = 1, AVG(actual_power) / 1000
-        BigDecimal actualPower = computeActualPower(actualRecords);
-        vo.setActualPower(actualPower);
-
-        // 3. forecastPower: AVG(power) / 1000
-        BigDecimal forecastPower = computeForecastPower(forecastRecords);
-        vo.setForecastPower(forecastPower);
-
-        // 4. RMSE
-        BigDecimal rmse = computeRmse(actualRecords, forecastRecords);
-        vo.setRootMeanSquareError(rmse);
-
-        // 5. MAE
-        BigDecimal mae = computeMae(actualRecords, forecastRecords);
-        vo.setMeanAbsoluteError(mae);
-
-        // 6. correlationCoefficientR
-        BigDecimal corr = computeCorrelation(actualRecords, forecastRecords);
-        vo.setCorrelationCoefficientR(corr);
-
-        // 7. maximumErrorPassRate: 基于逐点校验的合格率
-        BigDecimal passRate = computeMaximumErrorPassRate(actualRecords, forecastRecords, operatingCapacity);
-        vo.setMaximumErrorPassRate(passRate);
-    }
-
-    /**
-     * 计算开机容量
-     */
-    private BigDecimal computeOperatingCapacity(List<DataElectricityLocal> records)
-    {
-        double maxPower = 0.0;
-        for (DataElectricityLocal r : records)
-        {
-            if (r.getDeviceStatus() != null && r.getDeviceStatus() == 0
-                    && r.getGridStatus() != null && r.getGridStatus() == 1)
-            {
-                Double ap = r.getActualPower();
-                if (ap != null && ap > maxPower)
-                {
-                    maxPower = ap;
-                }
-            }
-        }
-        return BigDecimal.valueOf(maxPower / 1000.0);
-    }
-
-    /**
-     * 计算实发功率
-     */
-    private BigDecimal computeActualPower(List<DataElectricityLocal> records)
-    {
-        double sum = 0.0;
-        int count = 0;
-        for (DataElectricityLocal r : records)
-        {
-            if (r.getGridStatus() != null && r.getGridStatus() == 1)
-            {
-                Double ap = r.getActualPower();
-                if (ap != null)
-                {
-                    sum += ap;
-                    count++;
-                }
-            }
-        }
-        if (count == 0)
-        {
-            return BigDecimal.ZERO;
-        }
-        return BigDecimal.valueOf(sum / count / 1000.0);
-    }
-
-    /**
-     * 计算预测功率
-     */
-    private BigDecimal computeForecastPower(List<DataShortTermPowerForecastIssued> records)
-    {
-        double sum = 0.0;
-        int count = 0;
-        for (DataShortTermPowerForecastIssued r : records)
-        {
-            String power = r.getPower();
-            if (StringUtils.isNotEmpty(power))
-            {
-                try
-                {
-                    sum += Double.parseDouble(power.trim());
-                    count++;
-                }
-                catch (NumberFormatException e)
-                {
-                    // skip
-                }
-            }
-        }
-        if (count == 0)
-        {
-            return BigDecimal.ZERO;
-        }
-        return BigDecimal.valueOf(sum / count / 1000.0);
-    }
-
-    /**
-     * 计算RMSE
-     */
-    private BigDecimal computeRmse(List<DataElectricityLocal> actualRecords,
-            List<DataShortTermPowerForecastIssued> forecastRecords)
-    {
-        // 按时间戳聚合预测数据(以分钟级时间戳为key)
-        Map<Long, Double> forecastMap = buildForecastMap(forecastRecords);
-
-        if (forecastMap.isEmpty())
-        {
-            return BigDecimal.ZERO;
-        }
-
-        double sumSquaredError = 0.0;
-        int count = 0;
-
-        for (DataElectricityLocal r : actualRecords)
-        {
-            if (r.getTm() == null) continue;
-            Long ts = r.getTm().getTime() / 1000;
-            Double fp = forecastMap.get(ts);
-            if (fp == null) continue;
-
-            Double ap = r.getActualPower();
-            if (ap == null) continue;
-
-            double diffMW = (ap - fp) / 1000.0;
-            sumSquaredError += diffMW * diffMW;
-            count++;
-        }
-
-        if (count == 0)
-        {
-            return BigDecimal.ZERO;
-        }
-
-        double rmse = Math.sqrt(sumSquaredError / count);
-        return BigDecimal.valueOf(rmse).setScale(4, RoundingMode.HALF_UP);
-    }
-
-    /**
-     * 计算MAE
-     */
-    private BigDecimal computeMae(List<DataElectricityLocal> actualRecords,
-            List<DataShortTermPowerForecastIssued> forecastRecords)
-    {
-        Map<Long, Double> forecastMap = buildForecastMap(forecastRecords);
-
-        if (forecastMap.isEmpty())
-        {
-            return BigDecimal.ZERO;
-        }
-
-        double sumAbsError = 0.0;
-        int count = 0;
-
-        for (DataElectricityLocal r : actualRecords)
-        {
-            if (r.getTm() == null) continue;
-            Long ts = r.getTm().getTime() / 1000;
-            Double fp = forecastMap.get(ts);
-            if (fp == null) continue;
-
-            Double ap = r.getActualPower();
-            if (ap == null) continue;
-
-            double absErrorMW = Math.abs(ap - fp) / 1000.0;
-            sumAbsError += absErrorMW;
-            count++;
-        }
-
-        if (count == 0)
-        {
-            return BigDecimal.ZERO;
-        }
-
-        double mae = sumAbsError / count;
-        return BigDecimal.valueOf(mae).setScale(4, RoundingMode.HALF_UP);
-    }
-
-    /**
-     * 计算相关性系数 R
-     */
-    private BigDecimal computeCorrelation(List<DataElectricityLocal> actualRecords,
-            List<DataShortTermPowerForecastIssued> forecastRecords)
-    {
-        Map<Long, Double> forecastMap = buildForecastMap(forecastRecords);
-
-        if (forecastMap.isEmpty())
-        {
-            return BigDecimal.ZERO;
-        }
-
-        // 收集成对数据
-        List<Double> xList = new ArrayList<>();
-        List<Double> yList = new ArrayList<>();
-
-        for (DataElectricityLocal r : actualRecords)
-        {
-            if (r.getTm() == null) continue;
-            Long ts = r.getTm().getTime() / 1000;
-            Double fp = forecastMap.get(ts);
-            if (fp == null) continue;
-
-            Double ap = r.getActualPower();
-            if (ap == null) continue;
-
-            xList.add(ap / 1000.0);
-            yList.add(fp / 1000.0);
-        }
-
-        int n = xList.size();
-        if (n < 2)
-        {
-            return BigDecimal.ZERO;
-        }
-
-        // 计算均值
-        double meanX = xList.stream().mapToDouble(Double::doubleValue).average().orElse(0.0);
-        double meanY = yList.stream().mapToDouble(Double::doubleValue).average().orElse(0.0);
-
-        // 计算相关系数
-        double numerator = 0.0;
-        double sumSqX = 0.0;
-        double sumSqY = 0.0;
-
-        for (int i = 0; i < n; i++)
-        {
-            double dx = xList.get(i) - meanX;
-            double dy = yList.get(i) - meanY;
-            numerator += dx * dy;
-            sumSqX += dx * dx;
-            sumSqY += dy * dy;
-        }
-
-        double denominator = Math.sqrt(sumSqX * sumSqY);
-        if (denominator == 0.0)
-        {
-            return BigDecimal.ZERO;
-        }
-
-        double r = numerator / denominator;
-        return BigDecimal.valueOf(r).setScale(4, RoundingMode.HALF_UP);
-    }
-
-    /**
-     * 计算最大误差合格率
-     */
-    private BigDecimal computeMaximumErrorPassRate(List<DataElectricityLocal> actualRecords,
-            List<DataShortTermPowerForecastIssued> forecastRecords,
-            BigDecimal operatingCapacity)
-    {
-        if (operatingCapacity == null || operatingCapacity.compareTo(BigDecimal.ZERO) == 0)
-        {
-            return BigDecimal.ZERO;
-        }
-
-        String threshold = getErrorThreshold();
-        if (StringUtils.isEmpty(threshold))
-        {
-            return BigDecimal.ZERO;
-        }
-
-        double thresholdValue;
-        try
-        {
-            thresholdValue = Double.parseDouble(threshold);
-        }
-        catch (NumberFormatException e)
-        {
-            return BigDecimal.ZERO;
-        }
-
-        double capacityMW = operatingCapacity.doubleValue();
-        double passCount = 0;
-        double totalCount = 0;
-
-        // 基于时间戳逐点校验:ABS(actual - forecast) / 开机容量 <= 阈值
-        Map<Long, Double> forecastMap = buildForecastMap(forecastRecords);
-
-        for (DataElectricityLocal r : actualRecords)
-        {
-            if (r.getTm() == null || r.getActualPower() == null) continue;
-
-            Long ts = r.getTm().getTime() / 1000;
-            Double fp = forecastMap.get(ts);
-            if (fp == null) continue;
-
-            totalCount++;
-            double errorMW = Math.abs(r.getActualPower() - fp) / 1000.0;
-            if (errorMW <= thresholdValue * capacityMW)
-            {
-                passCount++;
-            }
-        }
-
-        if (totalCount == 0)
-        {
-            return BigDecimal.ZERO;
-        }
-
-        double rate = (passCount / totalCount) * 100.0;
-        return BigDecimal.valueOf(rate).setScale(2, RoundingMode.HALF_UP);
-    }
-
-    /**
-     * 构建预测数据映射:时间戳(秒) -> power(kW)
-     */
-    private Map<Long, Double> buildForecastMap(List<DataShortTermPowerForecastIssued> records)
-    {
-        Map<Long, Double> map = new LinkedHashMap<>();
-        if (records == null) return map;
-
-        for (DataShortTermPowerForecastIssued r : records)
-        {
-            if (r.getForecastTime() == null) continue;
-            String power = r.getPower();
-            if (StringUtils.isEmpty(power)) continue;
-
-            try
-            {
-                map.put(r.getForecastTime(), Double.parseDouble(power.trim()));
-            }
-            catch (NumberFormatException e)
-            {
-                // skip
-            }
-        }
-        return map;
-    }
-
-    /**
-     * 按日分组
-     */
-    private Map<String, List<DataElectricityLocal>> groupByDay(List<DataElectricityLocal> records)
-    {
-        return records.stream()
-                .filter(r -> r.getTm() != null)
-                .collect(Collectors.groupingBy(
-                        r -> LocalDate.ofInstant(r.getTm().toInstant(), ZONE_SHANGHAI)
-                                .format(DATE_FMT),
-                        LinkedHashMap::new,
-                        Collectors.toList()));
-    }
-
-    /**
-     * 按月分组
-     */
-    private Map<String, List<DataElectricityLocal>> groupByMonth(List<DataElectricityLocal> records)
-    {
-        return records.stream()
-                .filter(r -> r.getTm() != null)
-                .collect(Collectors.groupingBy(
-                        r ->
-                        {
-                            LocalDate ld = LocalDate.ofInstant(r.getTm().toInstant(), ZONE_SHANGHAI);
-                            return YearMonth.of(ld.getYear(), ld.getMonth()).format(MONTH_FMT);
-                        },
-                        LinkedHashMap::new,
-                        Collectors.toList()));
-    }
-
-    /**
-     * 按年分组
-     */
-    private Map<String, List<DataElectricityLocal>> groupByYear(List<DataElectricityLocal> records)
-    {
-        return records.stream()
-                .filter(r -> r.getTm() != null)
-                .collect(Collectors.groupingBy(
-                        r -> String.valueOf(LocalDate.ofInstant(r.getTm().toInstant(), ZONE_SHANGHAI).getYear()),
-                        LinkedHashMap::new,
-                        Collectors.toList()));
-    }
-
-    /**
-     * 按日分组预测数据
-     */
-    private Map<String, List<DataShortTermPowerForecastIssued>> groupForecastByDay(
-            List<DataShortTermPowerForecastIssued> records)
-    {
-        return records.stream()
-                .filter(r -> r.getForecastTime() != null)
-                .collect(Collectors.groupingBy(
-                        r -> LocalDate.ofEpochDay(r.getForecastTime() / 86400L)
-                                .format(DATE_FMT),
-                        LinkedHashMap::new,
-                        Collectors.toList()));
-    }
-
-    /**
-     * 按月分组预测数据
-     */
-    private Map<String, List<DataShortTermPowerForecastIssued>> groupForecastByMonth(
-            List<DataShortTermPowerForecastIssued> records)
-    {
-        return records.stream()
-                .filter(r -> r.getForecastTime() != null)
-                .collect(Collectors.groupingBy(
-                        r ->
-                        {
-                            LocalDate ld = LocalDate.ofEpochDay(r.getForecastTime() / 86400L);
-                            return YearMonth.of(ld.getYear(), ld.getMonth()).format(MONTH_FMT);
-                        },
-                        LinkedHashMap::new,
-                        Collectors.toList()));
-    }
-
-    /**
-     * 按年分组预测数据
-     */
-    private Map<String, List<DataShortTermPowerForecastIssued>> groupForecastByYear(
-            List<DataShortTermPowerForecastIssued> records)
-    {
-        return records.stream()
-                .filter(r -> r.getForecastTime() != null)
-                .collect(Collectors.groupingBy(
-                        r -> String.valueOf(LocalDate.ofEpochDay(r.getForecastTime() / 86400L).getYear()),
-                        LinkedHashMap::new,
-                        Collectors.toList()));
-    }
-
-    /**
-     * 安全解析Long
-     */
-    private Long parseLong(String value)
-    {
-        if (value == null || value.isEmpty()) return 0L;
-        try
-        {
-            return Long.parseLong(value.trim());
-        }
-        catch (NumberFormatException e)
-        {
-            return 0L;
-        }
-    }
-
-    /**
-     * 获取误差阈值
-     */
-    private String getErrorThreshold()
-    {
-        List<SysDictData> dictList = dictTypeService.selectDictDataByType(DICT_TYPE_SHORT_TERM_ERROR_THRESHOLD);
-        if (dictList != null && !dictList.isEmpty())
-        {
-            return dictList.get(0).getDictValue();
-        }
-        return null;
-    }
-
-    /**
-     * 刷新阈值配置
-     */
-    private void refreshErrorThreshold()
-    {
-        try
-        {
-            List<SysDictData> dictList = dictTypeService.selectDictDataByType(DICT_TYPE_SHORT_TERM_ERROR_THRESHOLD);
-            if (dictList != null && !dictList.isEmpty())
-            {
-                errorThreshold = dictList.get(0).getDictValue();
-            }
-        }
-        catch (Exception e)
-        {
-            errorThreshold = "0.2"; // 默认阈值 20%
-        }
-    }
-}

+ 0 - 780
forecast-backend-server/src/main/java/com/ufo/project/data/service/impl/UltraShortTermPowerForecastReportServiceImpl.java

@@ -1,780 +0,0 @@
-package com.ufo.project.data.service.impl;
-
-import java.math.BigDecimal;
-import java.math.RoundingMode;
-import java.time.LocalDate;
-import java.time.YearMonth;
-import java.time.ZoneId;
-import java.time.ZoneOffset;
-import java.time.format.DateTimeFormatter;
-import java.util.ArrayList;
-import java.util.Collections;
-import java.util.LinkedHashMap;
-import java.util.List;
-import java.util.Map;
-import java.util.Map.Entry;
-import java.util.stream.Collectors;
-import javax.annotation.PostConstruct;
-import org.springframework.beans.factory.annotation.Autowired;
-import org.springframework.stereotype.Service;
-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.data.domain.vo.UltraShortTermPowerForecastReportQuery;
-import com.ufo.project.data.domain.vo.UltraShortTermPowerForecastReportVO;
-import com.ufo.project.data.service.IUltraShortTermPowerForecastReportService;
-import com.ufo.project.forecast.supershort.domain.DataSuperShortTermForecastIssued;
-import com.ufo.project.forecast.supershort.domain.DataUltraShortTermPowerForecasting;
-import com.ufo.project.forecast.supershort.service.IDataSuperShortTermForecastIssuedService;
-import com.ufo.project.forecast.supershort.service.IDataUltraShortTermPowerForecastingService;
-import com.ufo.project.model.domain.DataElectricityLocal;
-import com.ufo.project.model.service.IDataElectricityLocalService;
-
-/**
- * 超短期预测报表Service业务层处理
- *
- * @author ufo
- * @date 2026-09-07
- */
-@Service
-public class UltraShortTermPowerForecastReportServiceImpl implements IUltraShortTermPowerForecastReportService
-{
-    private static final int SCALE = 4;
-    private static final long SECONDS_PER_DAY = 86400L;
-    private static final long SECONDS_PER_HOUR = 3600L;
-    private static final long SECONDS_PER_4H = SECONDS_PER_HOUR * 4L;
-
-    private static final DateTimeFormatter DATE_FMT = DateTimeFormatter.ofPattern("yyyy-MM-dd");
-    private static final DateTimeFormatter MONTH_FMT = DateTimeFormatter.ofPattern("yyyy-MM");
-    private static final DateTimeFormatter YEAR_FMT = DateTimeFormatter.ofPattern("yyyy");
-
-    private static final ZoneId ZONE_SHANGHAI = ZoneId.of("Asia/Shanghai");
-    private static final ZoneOffset ZONE_8 = ZoneOffset.ofHours(8);
-
-    @Autowired
-    private IDataElectricityLocalService electricityLocalService;
-
-    @Autowired
-    private IDataSuperShortTermForecastIssuedService superShortService;
-
-    @Autowired
-    private IDataUltraShortTermPowerForecastingService ultraForecastService;
-
-    /**
-     * 超短期预测报表查询
-     */
-    @Override
-    public List<UltraShortTermPowerForecastReportVO> selectReportList(UltraShortTermPowerForecastReportQuery query)
-    {
-        String type = query.getType();
-        String entityId = query.getEntityId();
-        String startTime = query.getStartTime();
-        String endTime = query.getEndTime();
-
-        // 1. 获取实发功率数据
-        String startStr = startTime + " 00:00:00";
-        String endStr = endTime + " 23:59:59";
-        List<DataElectricityLocal> actualList = electricityLocalService.selectActualPowerList(
-                parseLong(entityId), startStr, endStr);
-        if (actualList == null || actualList.isEmpty())
-        {
-            return Collections.emptyList();
-        }
-
-        // 2. 获取超短期预测功率数据
-        Long startSec = toUnixSeconds(startStr);
-        Long endSec = toUnixSeconds(endStr);
-        List<DataSuperShortTermForecastIssued> forecastList = selectSuperShortByTimeRange(entityId, startSec, endSec);
-
-        // 3. 获取超短期预报数据(提前4h)
-        Long startSec4h = startSec - SECONDS_PER_4H;
-        List<DataUltraShortTermPowerForecasting> ultraForecastList = ultraForecastService
-                .selectByTimeRange(entityId, startSec4h, endSec);
-
-        // 4. 按基准类型分组
-        switch (type)
-        {
-            case "daily":
-                return buildDailyReport(actualList, forecastList, ultraForecastList);
-            case "monthly":
-                return buildMonthlyReport(actualList, forecastList, ultraForecastList);
-            case "yearly":
-                return buildYearlyReport(actualList, forecastList, ultraForecastList);
-            default:
-                return Collections.emptyList();
-        }
-    }
-
-    /**
-     * 构建日报
-     */
-    private List<UltraShortTermPowerForecastReportVO> buildDailyReport(
-            List<DataElectricityLocal> actualList,
-            List<DataSuperShortTermForecastIssued> forecastList,
-            List<DataUltraShortTermPowerForecasting> ultraForecastList)
-    {
-        Map<String, List<DataElectricityLocal>> dailyMap = groupByDay(actualList);
-        Map<String, List<DataSuperShortTermForecastIssued>> forecastDailyMap = groupForecastByDay(forecastList);
-        Map<Long, List<DataUltraShortTermPowerForecasting>> ultraForecastMap = groupUltraForecastByStartSec(ultraForecastList);
-
-        List<UltraShortTermPowerForecastReportVO> result = new ArrayList<>();
-        for (Entry<String, List<DataElectricityLocal>> entry : dailyMap.entrySet())
-        {
-            String day = entry.getKey();
-            List<DataElectricityLocal> records = entry.getValue();
-            List<DataSuperShortTermForecastIssued> forecastRecords = forecastDailyMap.getOrDefault(day, Collections.emptyList());
-            List<DataUltraShortTermPowerForecasting> ultraRecords = collectUltraForDay(day, ultraForecastMap);
-
-            UltraShortTermPowerForecastReportVO vo = new UltraShortTermPowerForecastReportVO();
-            vo.setTime(day);
-            computeMetrics(vo, records, forecastRecords, ultraRecords);
-            result.add(vo);
-        }
-        return result;
-    }
-
-    /**
-     * 构建月报
-     */
-    private List<UltraShortTermPowerForecastReportVO> buildMonthlyReport(
-            List<DataElectricityLocal> actualList,
-            List<DataSuperShortTermForecastIssued> forecastList,
-            List<DataUltraShortTermPowerForecasting> ultraForecastList)
-    {
-        Map<String, List<DataElectricityLocal>> monthlyMap = groupByMonth(actualList);
-        Map<String, List<DataSuperShortTermForecastIssued>> forecastMonthlyMap = groupForecastByMonth(forecastList);
-        Map<Long, List<DataUltraShortTermPowerForecasting>> ultraForecastMap = groupUltraForecastByStartSec(ultraForecastList);
-
-        List<UltraShortTermPowerForecastReportVO> result = new ArrayList<>();
-        for (Entry<String, List<DataElectricityLocal>> entry : monthlyMap.entrySet())
-        {
-            String month = entry.getKey();
-            List<DataElectricityLocal> records = entry.getValue();
-            List<DataSuperShortTermForecastIssued> forecastRecords =
-                    forecastMonthlyMap.getOrDefault(month, Collections.emptyList());
-            List<DataUltraShortTermPowerForecasting> ultraRecords = collectUltraForMonth(month, ultraForecastMap);
-
-            UltraShortTermPowerForecastReportVO vo = new UltraShortTermPowerForecastReportVO();
-            vo.setTime(month);
-            computeMetrics(vo, records, forecastRecords, ultraRecords);
-            result.add(vo);
-        }
-        return result;
-    }
-
-    /**
-     * 构建年报
-     */
-    private List<UltraShortTermPowerForecastReportVO> buildYearlyReport(
-            List<DataElectricityLocal> actualList,
-            List<DataSuperShortTermForecastIssued> forecastList,
-            List<DataUltraShortTermPowerForecasting> ultraForecastList)
-    {
-        Map<String, List<DataElectricityLocal>> yearlyMap = groupByYear(actualList);
-        Map<String, List<DataSuperShortTermForecastIssued>> forecastYearlyMap = groupForecastByYear(forecastList);
-        Map<Long, List<DataUltraShortTermPowerForecasting>> ultraForecastMap = groupUltraForecastByStartSec(ultraForecastList);
-
-        List<UltraShortTermPowerForecastReportVO> result = new ArrayList<>();
-        for (Entry<String, List<DataElectricityLocal>> entry : yearlyMap.entrySet())
-        {
-            String year = entry.getKey();
-            List<DataElectricityLocal> records = entry.getValue();
-            List<DataSuperShortTermForecastIssued> forecastRecords =
-                    forecastYearlyMap.getOrDefault(year, Collections.emptyList());
-            List<DataUltraShortTermPowerForecasting> ultraRecords = collectUltraForYear(year, ultraForecastMap);
-
-            UltraShortTermPowerForecastReportVO vo = new UltraShortTermPowerForecastReportVO();
-            vo.setTime(year);
-            computeMetrics(vo, records, forecastRecords, ultraRecords);
-            result.add(vo);
-        }
-        return result;
-    }
-
-    /**
-     * 计算指标
-     */
-    private void computeMetrics(UltraShortTermPowerForecastReportVO vo,
-            List<DataElectricityLocal> actualRecords,
-            List<DataSuperShortTermForecastIssued> forecastRecords,
-            List<DataUltraShortTermPowerForecasting> ultraRecords)
-    {
-        // 1. 开机容量
-        BigDecimal operatingCapacity = computeOperatingCapacity(actualRecords);
-        vo.setOperatingCapacity(operatingCapacity);
-
-        // 2. 实发功率
-        BigDecimal actualPower = computeActualPower(actualRecords);
-        vo.setActualPower(actualPower);
-
-        // 3. 预测功率(超短期预测功率)
-        BigDecimal forecastPower = computeForecastPower(forecastRecords);
-        vo.setForecastPower(forecastPower);
-
-        // 4. RMSE
-        BigDecimal rmse = computeRmse(actualRecords, forecastRecords);
-        vo.setRootMeanSquareError(rmse);
-
-        // 5. MAE
-        BigDecimal mae = computeMae(actualRecords, forecastRecords);
-        vo.setMeanAbsoluteError(mae);
-
-        // 6. 相关性系数
-        BigDecimal corr = computeCorrelation(actualRecords, forecastRecords);
-        vo.setCorrelationCoefficientR(corr);
-
-        // 7. 4小时前预测准确率
-        BigDecimal accuracy = computeAheadForecastAccuracy4h(actualRecords, ultraRecords, operatingCapacity);
-        vo.setAheadForecastAccuracy4h(accuracy);
-    }
-
-    // ==================== 基础计算 ====================
-
-    private BigDecimal computeOperatingCapacity(List<DataElectricityLocal> records)
-    {
-        double maxPower = 0.0;
-        for (DataElectricityLocal r : records)
-        {
-            if (r.getDeviceStatus() != null && r.getDeviceStatus() == 0
-                    && r.getGridStatus() != null && r.getGridStatus() == 1)
-            {
-                Double ap = r.getActualPower();
-                if (ap != null && ap > maxPower)
-                {
-                    maxPower = ap;
-                }
-            }
-        }
-        return BigDecimal.valueOf(maxPower / 1000.0);
-    }
-
-    private BigDecimal computeActualPower(List<DataElectricityLocal> records)
-    {
-        double sum = 0.0;
-        int count = 0;
-        for (DataElectricityLocal r : records)
-        {
-            if (r.getGridStatus() != null && r.getGridStatus() == 1)
-            {
-                Double ap = r.getActualPower();
-                if (ap != null)
-                {
-                    sum += ap;
-                    count++;
-                }
-            }
-        }
-        if (count == 0) return BigDecimal.ZERO;
-        return BigDecimal.valueOf(sum / count / 1000.0);
-    }
-
-    private BigDecimal computeForecastPower(List<DataSuperShortTermForecastIssued> records)
-    {
-        double sum = 0.0;
-        int count = 0;
-        for (DataSuperShortTermForecastIssued r : records)
-        {
-            String power = r.getPower();
-            if (StringUtils.isNotEmpty(power))
-            {
-                try
-                {
-                    sum += Double.parseDouble(power.trim());
-                    count++;
-                }
-                catch (NumberFormatException e)
-                {
-                    // skip
-                }
-            }
-        }
-        if (count == 0) return BigDecimal.ZERO;
-        return BigDecimal.valueOf(sum / count / 1000.0);
-    }
-
-    private BigDecimal computeRmse(List<DataElectricityLocal> actualRecords,
-            List<DataSuperShortTermForecastIssued> forecastRecords)
-    {
-        Map<Long, Double> forecastMap = buildForecastMap(forecastRecords);
-        if (forecastMap.isEmpty()) return BigDecimal.ZERO;
-
-        double sumSquaredError = 0.0;
-        int count = 0;
-
-        for (DataElectricityLocal r : actualRecords)
-        {
-            if (r.getTm() == null) continue;
-            long ts = r.getTm().toInstant().atZone(ZONE_SHANGHAI).toEpochSecond();
-            Double fp = forecastMap.get(ts);
-            if (fp == null) continue;
-
-            Double ap = r.getActualPower();
-            if (ap == null) continue;
-
-            double diffMW = (ap - fp) / 1000.0;
-            sumSquaredError += diffMW * diffMW;
-            count++;
-        }
-
-        if (count == 0) return BigDecimal.ZERO;
-        return BigDecimal.valueOf(Math.sqrt(sumSquaredError / count)).setScale(SCALE, RoundingMode.HALF_UP);
-    }
-
-    private BigDecimal computeMae(List<DataElectricityLocal> actualRecords,
-            List<DataSuperShortTermForecastIssued> forecastRecords)
-    {
-        Map<Long, Double> forecastMap = buildForecastMap(forecastRecords);
-        if (forecastMap.isEmpty()) return BigDecimal.ZERO;
-
-        double sumAbsError = 0.0;
-        int count = 0;
-
-        for (DataElectricityLocal r : actualRecords)
-        {
-            if (r.getTm() == null) continue;
-            long ts = r.getTm().toInstant().atZone(ZONE_SHANGHAI).toEpochSecond();
-            Double fp = forecastMap.get(ts);
-            if (fp == null) continue;
-
-            Double ap = r.getActualPower();
-            if (ap == null) continue;
-
-            double absErrorMW = Math.abs(ap - fp) / 1000.0;
-            sumAbsError += absErrorMW;
-            count++;
-        }
-
-        if (count == 0) return BigDecimal.ZERO;
-        return BigDecimal.valueOf(sumAbsError / count).setScale(SCALE, RoundingMode.HALF_UP);
-    }
-
-    private BigDecimal computeCorrelation(List<DataElectricityLocal> actualRecords,
-            List<DataSuperShortTermForecastIssued> forecastRecords)
-    {
-        Map<Long, Double> forecastMap = buildForecastMap(forecastRecords);
-        if (forecastMap.isEmpty()) return BigDecimal.ZERO;
-
-        List<Double> xList = new ArrayList<>();
-        List<Double> yList = new ArrayList<>();
-
-        for (DataElectricityLocal r : actualRecords)
-        {
-            if (r.getTm() == null) continue;
-            long ts = r.getTm().toInstant().atZone(ZONE_SHANGHAI).toEpochSecond();
-            Double fp = forecastMap.get(ts);
-            if (fp == null) continue;
-
-            Double ap = r.getActualPower();
-            if (ap == null) continue;
-
-            xList.add(ap / 1000.0);
-            yList.add(fp / 1000.0);
-        }
-
-        int n = xList.size();
-        if (n < 2) return BigDecimal.ZERO;
-
-        double meanX = xList.stream().mapToDouble(Double::doubleValue).average().orElse(0.0);
-        double meanY = yList.stream().mapToDouble(Double::doubleValue).average().orElse(0.0);
-
-        double numerator = 0.0;
-        double sumSqX = 0.0;
-        double sumSqY = 0.0;
-
-        for (int i = 0; i < n; i++)
-        {
-            double dx = xList.get(i) - meanX;
-            double dy = yList.get(i) - meanY;
-            numerator += dx * dy;
-            sumSqX += dx * dx;
-            sumSqY += dy * dy;
-        }
-
-        double denominator = Math.sqrt(sumSqX * sumSqY);
-        if (denominator == 0.0) return BigDecimal.ZERO;
-
-        double r = numerator / denominator;
-        return BigDecimal.valueOf(r).setScale(SCALE, RoundingMode.HALF_UP);
-    }
-
-    /**
-     * 计算4小时前预测准确率
-     *
-     * 对每个实际数据点,找到start_time匹配的超短期预报记录
-     * 从该记录的power15~power240字段提取16个预测值,取算术平均得P_Pi
-     * error_i = (P_Mi - P_Pi) / max(P_Mi, 0.2 * Cap)
-     * ACC = 1 - sqrt((1/N) * sum(error_i^2))
-     */
-    private BigDecimal computeAheadForecastAccuracy4h(List<DataElectricityLocal> actualRecords,
-            List<DataUltraShortTermPowerForecasting> ultraRecords,
-            BigDecimal operatingCapacity)
-    {
-        if (ultraRecords == null || ultraRecords.isEmpty()) return BigDecimal.ZERO;
-        if (operatingCapacity == null || operatingCapacity.compareTo(BigDecimal.ZERO) == 0) return BigDecimal.ZERO;
-
-        double capacityMW = operatingCapacity.doubleValue();
-        double thresholdMW = Math.max(0.2 * capacityMW, 0.001); // 防止分母过小
-
-        // 构建超短期预报数据映射: start_time(秒) -> 记录
-        Map<Long, DataUltraShortTermPowerForecasting> ultraMap = new LinkedHashMap<>();
-        for (DataUltraShortTermPowerForecasting r : ultraRecords)
-        {
-            if (r.getStartTime() != null)
-            {
-                ultraMap.put(r.getStartTime(), r);
-            }
-        }
-
-        double sumSquaredError = 0.0;
-        int count = 0;
-
-        for (DataElectricityLocal actual : actualRecords)
-        {
-            if (actual.getTm() == null || actual.getActualPower() == null) continue;
-
-            // 实际数据的unix秒时间戳
-            long actualTs = actual.getTm().toInstant().atZone(ZONE_SHANGHAI).toEpochSecond();
-
-            // 查找start_time匹配的超短期预报记录
-            DataUltraShortTermPowerForecasting ultra = ultraMap.get(actualTs);
-            if (ultra == null) continue;
-
-            // 计算P_Pi = (power15 + power30 + ... + power240) / 16 的算术平均
-            double ppSum = 0.0;
-            int ppCount = 0;
-
-            String[] powerFields = {
-                    "power15", "power30", "power45", "power60",
-                    "power75", "power90", "power105", "power120",
-                    "power135", "power150", "power165", "power180",
-                    "power195", "power210", "power225", "power240"
-            };
-
-            for (String field : powerFields)
-            {
-                Double value = getPowerField(ultra, field);
-                if (value != null)
-                {
-                    ppSum += value;
-                    ppCount++;
-                }
-            }
-
-            if (ppCount == 0) continue;
-            double ppMean = ppSum / ppCount; // P_Pi (kW)
-
-            // P_Mi (kW)
-            double pm = actual.getActualPower();
-
-            // error_i = (P_Mi - P_Pi) / max(P_Mi, 0.2 * Cap)
-            double denominator = Math.max(Math.abs(pm), thresholdMW);
-            double error = (pm - ppMean) / denominator;
-
-            sumSquaredError += error * error;
-            count++;
-        }
-
-        if (count == 0) return BigDecimal.ZERO;
-
-        double acc = 1.0 - Math.sqrt(sumSquaredError / count);
-        return BigDecimal.valueOf(acc).setScale(SCALE, RoundingMode.HALF_UP);
-    }
-
-    /**
-     * 安全获取Power字段值
-     */
-    private Double getPowerField(DataUltraShortTermPowerForecasting record, String fieldName)
-    {
-        try
-        {
-            switch (fieldName)
-            {
-                case "power15":  return parseDouble(record.getPower15());
-                case "power30":  return parseDouble(record.getPower30());
-                case "power45":  return parseDouble(record.getPower45());
-                case "power60":  return parseDouble(record.getPower60());
-                case "power75":  return parseDouble(record.getPower75());
-                case "power90":  return parseDouble(record.getPower90());
-                case "power105": return parseDouble(record.getPower105());
-                case "power120": return parseDouble(record.getPower120());
-                case "power135": return parseDouble(record.getPower135());
-                case "power150": return parseDouble(record.getPower150());
-                case "power165": return parseDouble(record.getPower165());
-                case "power180": return parseDouble(record.getPower180());
-                case "power195": return parseDouble(record.getPower195());
-                case "power210": return parseDouble(record.getPower210());
-                case "power225": return parseDouble(record.getPower225());
-                case "power240": return parseDouble(record.getPower240());
-                default: return null;
-            }
-        }
-        catch (Exception e)
-        {
-            return null;
-        }
-    }
-
-    // ==================== 辅助方法 ====================
-
-    /**
-     * 构建超短期预测数据映射: unix秒 -> power(kW)
-     */
-    private Map<Long, Double> buildForecastMap(List<DataSuperShortTermForecastIssued> records)
-    {
-        Map<Long, Double> map = new LinkedHashMap<>();
-        if (records == null) return map;
-
-        for (DataSuperShortTermForecastIssued r : records)
-        {
-            String power = r.getPower();
-            if (StringUtils.isEmpty(power)) continue;
-            try
-            {
-                Double p = Double.parseDouble(power.trim());
-                if (r.getForecastTime() != null)
-                {
-                    map.put(r.getForecastTime(), p);
-                }
-                if (r.getStartTime() != null)
-                {
-                    map.putIfAbsent(r.getStartTime(), p);
-                }
-            }
-            catch (NumberFormatException e)
-            {
-                // skip
-            }
-        }
-        return map;
-    }
-
-    /**
-     * 安全解析String为Double
-     */
-    private Double parseDouble(String value)
-    {
-        if (value == null || value.isEmpty()) return 0.0;
-        try
-        {
-            return Double.parseDouble(value.trim());
-        }
-        catch (NumberFormatException e)
-        {
-            return 0.0;
-        }
-    }
-
-    /**
-     * 安全解析String为Long
-     */
-    private Long parseLong(String value)
-    {
-        if (value == null || value.isEmpty()) return 0L;
-        try
-        {
-            return Long.parseLong(value.trim());
-        }
-        catch (NumberFormatException e)
-        {
-            return 0L;
-        }
-    }
-
-    /**
-     * 将yyyy-MM-dd HH:mm:ss字符串转换为unix秒级时间戳
-     */
-    private Long toUnixSeconds(String dateTime)
-    {
-        return java.time.LocalDateTime.parse(dateTime, DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss"))
-                .atZone(ZONE_8)
-                .toInstant()
-                .getEpochSecond();
-    }
-
-    /**
-     * 按日分组
-     */
-    private Map<String, List<DataElectricityLocal>> groupByDay(List<DataElectricityLocal> records)
-    {
-        return records.stream()
-                .filter(r -> r.getTm() != null)
-                .collect(Collectors.groupingBy(
-                        r -> LocalDate.ofInstant(r.getTm().toInstant(), ZONE_SHANGHAI).format(DATE_FMT),
-                        LinkedHashMap::new,
-                        Collectors.toList()));
-    }
-
-    /**
-     * 按月分组
-     */
-    private Map<String, List<DataElectricityLocal>> groupByMonth(List<DataElectricityLocal> records)
-    {
-        return records.stream()
-                .filter(r -> r.getTm() != null)
-                .collect(Collectors.groupingBy(
-                        r ->
-                        {
-                            LocalDate ld = LocalDate.ofInstant(r.getTm().toInstant(), ZONE_SHANGHAI);
-                            return YearMonth.of(ld.getYear(), ld.getMonth()).format(MONTH_FMT);
-                        },
-                        LinkedHashMap::new,
-                        Collectors.toList()));
-    }
-
-    /**
-     * 按年分组
-     */
-    private Map<String, List<DataElectricityLocal>> groupByYear(List<DataElectricityLocal> records)
-    {
-        return records.stream()
-                .filter(r -> r.getTm() != null)
-                .collect(Collectors.groupingBy(
-                        r -> String.valueOf(LocalDate.ofInstant(r.getTm().toInstant(), ZONE_SHANGHAI).getYear()),
-                        LinkedHashMap::new,
-                        Collectors.toList()));
-    }
-
-    /**
-     * 按日分组超短期预测数据
-     */
-    private Map<String, List<DataSuperShortTermForecastIssued>> groupForecastByDay(
-            List<DataSuperShortTermForecastIssued> records)
-    {
-        return records.stream()
-                .filter(r -> r.getForecastTime() != null)
-                .collect(Collectors.groupingBy(
-                        r -> LocalDate.ofEpochDay(r.getForecastTime() / SECONDS_PER_DAY).format(DATE_FMT),
-                        LinkedHashMap::new,
-                        Collectors.toList()));
-    }
-
-    /**
-     * 按月分组超短期预测数据
-     */
-    private Map<String, List<DataSuperShortTermForecastIssued>> groupForecastByMonth(
-            List<DataSuperShortTermForecastIssued> records)
-    {
-        return records.stream()
-                .filter(r -> r.getForecastTime() != null)
-                .collect(Collectors.groupingBy(
-                        r ->
-                        {
-                            LocalDate ld = LocalDate.ofEpochDay(r.getForecastTime() / SECONDS_PER_DAY);
-                            return YearMonth.of(ld.getYear(), ld.getMonth()).format(MONTH_FMT);
-                        },
-                        LinkedHashMap::new,
-                        Collectors.toList()));
-    }
-
-    /**
-     * 按年分组超短期预测数据
-     */
-    private Map<String, List<DataSuperShortTermForecastIssued>> groupForecastByYear(
-            List<DataSuperShortTermForecastIssued> records)
-    {
-        return records.stream()
-                .filter(r -> r.getForecastTime() != null)
-                .collect(Collectors.groupingBy(
-                        r -> String.valueOf(LocalDate.ofEpochDay(r.getForecastTime() / SECONDS_PER_DAY).getYear()),
-                        LinkedHashMap::new,
-                        Collectors.toList()));
-    }
-
-    /**
-     * 按start_time秒分组超短期预报数据
-     */
-    private Map<Long, List<DataUltraShortTermPowerForecasting>> groupUltraForecastByStartSec(
-            List<DataUltraShortTermPowerForecasting> records)
-    {
-        Map<Long, List<DataUltraShortTermPowerForecasting>> map = new LinkedHashMap<>();
-        if (records == null) return map;
-        for (DataUltraShortTermPowerForecasting r : records)
-        {
-            if (r.getStartTime() != null)
-            {
-                map.computeIfAbsent(r.getStartTime(), k -> new ArrayList<>()).add(r);
-            }
-        }
-        return map;
-    }
-
-    /**
-     * 收集某日对应的超短期预报记录
-     */
-    private List<DataUltraShortTermPowerForecasting> collectUltraForDay(
-            String day, Map<Long, List<DataUltraShortTermPowerForecasting>> ultraMap)
-    {
-        LocalDate ld = LocalDate.parse(day, DATE_FMT);
-        long dayStartSec = ld.atStartOfDay(ZONE_SHANGHAI).toInstant().getEpochSecond();
-        return collectByStartSec(dayStartSec, SECONDS_PER_DAY, ultraMap);
-    }
-
-    /**
-     * 收集某月对应的超短期预报记录
-     */
-    private List<DataUltraShortTermPowerForecasting> collectUltraForMonth(
-            String month, Map<Long, List<DataUltraShortTermPowerForecasting>> ultraMap)
-    {
-        YearMonth ym = YearMonth.parse(month, MONTH_FMT);
-        LocalDate startDate = ym.atDay(1);
-        LocalDate endDate = ym.atEndOfMonth();
-        long startSec = startDate.atStartOfDay(ZONE_SHANGHAI).toInstant().getEpochSecond();
-        long endSec = endDate.atTime(23, 59, 59).atZone(ZONE_SHANGHAI).toInstant().getEpochSecond();
-        long duration = endSec - startSec;
-        return collectByStartSecRange(startSec, duration, ultraMap);
-    }
-
-    /**
-     * 收集某年对应的超短期预报记录
-     */
-    private List<DataUltraShortTermPowerForecasting> collectUltraForYear(
-            String year, Map<Long, List<DataUltraShortTermPowerForecasting>> ultraMap)
-    {
-        int y = Integer.parseInt(year);
-        LocalDate startDate = LocalDate.of(y, 1, 1);
-        LocalDate endDate = LocalDate.of(y, 12, 31);
-        long startSec = startDate.atStartOfDay(ZONE_SHANGHAI).toInstant().getEpochSecond();
-        long endSec = endDate.atTime(23, 59, 59).atZone(ZONE_SHANGHAI).toInstant().getEpochSecond();
-        long duration = endSec - startSec;
-        return collectByStartSecRange(startSec, duration, ultraMap);
-    }
-
-    /**
-     * 根据start_time范围收集超短期预报记录
-     */
-    private List<DataUltraShortTermPowerForecasting> collectByStartSec(
-            long startSec, long duration, Map<Long, List<DataUltraShortTermPowerForecasting>> ultraMap)
-    {
-        long endSec = startSec + duration;
-        return ultraMap.keySet().stream()
-                .filter(k -> k >= startSec && k < endSec)
-                .flatMap(k -> ultraMap.get(k).stream())
-                .collect(Collectors.toList());
-    }
-
-    private List<DataUltraShortTermPowerForecasting> collectByStartSecRange(
-            long startSec, long duration, Map<Long, List<DataUltraShortTermPowerForecasting>> ultraMap)
-    {
-        long endSec = startSec + duration;
-        List<DataUltraShortTermPowerForecasting> result = new ArrayList<>();
-        for (long k = startSec; k < endSec; k += SECONDS_PER_DAY)
-        {
-            List<DataUltraShortTermPowerForecasting> dayRecords = collectByStartSec(k, SECONDS_PER_DAY, ultraMap);
-            result.addAll(dayRecords);
-        }
-        return result;
-    }
-
-    /**
-     * 查询超短期预测功率数据列表
-     */
-    private List<DataSuperShortTermForecastIssued> selectSuperShortByTimeRange(
-            String entityId, Long startTime, Long endTime)
-    {
-        DataSuperShortTermForecastIssued query = new DataSuperShortTermForecastIssued();
-        query.setEntityId(entityId);
-        query.setForecastStartTime(startTime);
-        query.setForecastEndTime(endTime);
-        return superShortService.selectDataSuperShortTermForecastIssuedList(query);
-    }
-}

+ 0 - 4
forecast-backend-server/src/main/java/com/ufo/project/forecast/supershort/domain/DataUltraShortTermPowerForecasting.java

@@ -47,10 +47,6 @@ public class DataUltraShortTermPowerForecasting extends BaseEntity
     @Excel(name = "起报时间", dateFormat = "yyyy-MM-dd HH:mm:ss")
     private Long startTime;
 
-    /** 预报时间 */
-    @Excel(name = "预报时间", dateFormat = "yyyy-MM-dd HH:mm:ss")
-    private Long forecastTime;
-
     /** 实发功率 */
     @Excel(name = "实发功率")
     private String power;

+ 6 - 6
forecast-backend-server/src/main/java/com/ufo/project/weather/domain/DataWeatherLocal.java

@@ -32,7 +32,7 @@ public class DataWeatherLocal extends BaseEntity
 
     /** 斜面辐照度,单位 W/m² */
     @Excel(name = "斜面辐照度,单位 W/m²")
-    private Double irradiance;
+    private Double inclinedIrradiance;
 
     /** 温度,单位 ℃ */
     @Excel(name = "温度,单位 ℃")
@@ -81,14 +81,14 @@ public class DataWeatherLocal extends BaseEntity
     {
         return horizontalIrradiance;
     }
-    public void setIrradiance(Double irradiance) 
+    public void setInclinedIrradiance(Double inclinedIrradiance) 
     {
-        this.irradiance = irradiance;
+        this.inclinedIrradiance = inclinedIrradiance;
     }
 
-    public Double getIrradiance() 
+    public Double getInclinedIrradiance() 
     {
-        return irradiance;
+        return inclinedIrradiance;
     }
     public void setTemperature(Double temperature) 
     {
@@ -142,7 +142,7 @@ public class DataWeatherLocal extends BaseEntity
             .append("tm", getTm())
             .append("deviceId", getConfigStationId())
             .append("horizontalIrradiance", getHorizontalIrradiance())
-            .append("irradiance", getIrradiance())
+            .append("inclinedIrradiance", getInclinedIrradiance())
             .append("temperature", getTemperature())
             .append("pressure", getPressure())
             .append("humidity", getHumidity())

+ 0 - 5
forecast-backend-server/src/main/resources/mybatis/supershort/DataUltraShortTermPowerForecastingMapper.xml

@@ -13,7 +13,6 @@ PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
         <result property="entityName"    column="entity_name"    />
         <result property="createTime"    column="create_time"    />
         <result property="startTime"    column="start_time"    />
-        <result property="forecastTime"    column="forecast_time"    />
         <result property="power"    column="power"    />
         <result property="power15"    column="power15"    />
         <result property="power30"    column="power30"    />
@@ -46,7 +45,6 @@ PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
             <if test="entityType != null "> and entity_type = #{entityType}</if>
             <if test="entityName != null  and entityName != ''"> and entity_name like concat('%', #{entityName}, '%')</if>
             <if test="startTime != null "> and start_time = #{startTime}</if>
-            <if test="forecastTime != null "> and forecast_time = #{forecastTime}</if>
             <if test="power != null  and power != ''"> and power = #{power}</if>
             <if test="power15 != null  and power15 != ''"> and power15 = #{power15}</if>
             <if test="power30 != null  and power30 != ''"> and power30 = #{power30}</if>
@@ -88,7 +86,6 @@ PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
             <if test="entityName != null">entity_name,</if>
             <if test="createTime != null">create_time,</if>
             <if test="startTime != null">start_time,</if>
-            <if test="startTime != null">forecast_time,</if>
             <if test="power != null">power,</if>
             <if test="power15 != null">power15,</if>
             <if test="power30 != null">power30,</if>
@@ -115,7 +112,6 @@ PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
             <if test="entityName != null">#{entityName},</if>
             <if test="createTime != null">#{createTime},</if>
             <if test="startTime != null">#{startTime},</if>
-            <if test="forecastTime != null">#{forecastTime},</if>
             <if test="power != null">#{power},</if>
             <if test="power15 != null">#{power15},</if>
             <if test="power30 != null">#{power30},</if>
@@ -146,7 +142,6 @@ PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
             <if test="entityName != null">entity_name = #{entityName},</if>
             <if test="createTime != null">create_time = #{createTime},</if>
             <if test="startTime != null">start_time = #{startTime},</if>
-            <if test="forecastTime != null">forecast_time = #{forecastTime},</if>
             <if test="power != null">power = #{power},</if>
             <if test="power15 != null">power15 = #{power15},</if>
             <if test="power30 != null">power30 = #{power30},</if>

+ 6 - 6
forecast-backend-server/src/main/resources/mybatis/weather/DataWeatherLocalMapper.xml

@@ -8,7 +8,7 @@ PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
         <result property="tm"    column="tm"    />
         <result property="configStationId"    column="config_station_id"    />
         <result property="horizontalIrradiance"    column="horizontal_irradiance"    />
-        <result property="irradiance"    column="irradiance"    />
+        <result property="inclinedIrradiance"    column="inclined_irradiance"    />
         <result property="temperature"    column="temperature"    />
         <result property="pressure"    column="pressure"    />
         <result property="humidity"    column="humidity"    />
@@ -17,7 +17,7 @@ PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
     </resultMap>
 
     <sql id="selectDataWeatherLocalVo">
-        select tm, config_station_id, horizontal_irradiance, irradiance, temperature, pressure, humidity, wind_speed, wind_direction from data_weather_local
+        select tm, config_station_id, horizontal_irradiance, inclined_irradiance, temperature, pressure, humidity, wind_speed, wind_direction from data_weather_local
     </sql>
 
     <select id="selectDataWeatherLocalList" parameterType="DataWeatherLocal" resultMap="DataWeatherLocalResult">
@@ -26,7 +26,7 @@ PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
             <if test="tm != null "> and tm = #{tm}</if>
             <if test="configStationId != null "> and config_station_id = #{configStationId}</if>
             <if test="horizontalIrradiance != null "> and horizontal_irradiance = #{horizontalIrradiance}</if>
-            <if test="irradiance != null "> and irradiance = #{irradiance}</if>
+            <if test="inclinedIrradiance != null "> and inclined_irradiance = #{inclinedIrradiance}</if>
             <if test="temperature != null "> and temperature = #{temperature}</if>
             <if test="pressure != null "> and pressure = #{pressure}</if>
             <if test="humidity != null "> and humidity = #{humidity}</if>
@@ -60,7 +60,7 @@ PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
             <if test="tm != null">tm,</if>
             <if test="configStationId != null">config_station_id,</if>
             <if test="horizontalIrradiance != null">horizontal_irradiance,</if>
-            <if test="irradiance != null">irradiance,</if>
+            <if test="inclinedIrradiance != null">inclined_irradiance,</if>
             <if test="temperature != null">temperature,</if>
             <if test="pressure != null">pressure,</if>
             <if test="humidity != null">humidity,</if>
@@ -71,7 +71,7 @@ PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
             <if test="tm != null">#{tm},</if>
             <if test="configStationId != null">#{configStationId},</if>
             <if test="horizontalIrradiance != null">#{horizontalIrradiance},</if>
-            <if test="irradiance != null">#{irradiance},</if>
+            <if test="inclinedIrradiance != null">#{inclinedIrradiance},</if>
             <if test="temperature != null">#{temperature},</if>
             <if test="pressure != null">#{pressure},</if>
             <if test="humidity != null">#{humidity},</if>
@@ -85,7 +85,7 @@ PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
         <trim prefix="SET" suffixOverrides=",">
             <if test="configStationId != null">config_station_id = #{configStationId},</if>
             <if test="horizontalIrradiance != null">horizontal_irradiance = #{horizontalIrradiance},</if>
-            <if test="irradiance != null">irradiance = #{irradiance},</if>
+            <if test="inclinedIrradiance != null">inclined_irradiance = #{inclinedIrradiance},</if>
             <if test="temperature != null">temperature = #{temperature},</if>
             <if test="pressure != null">pressure = #{pressure},</if>
             <if test="humidity != null">humidity = #{humidity},</if>

+ 0 - 1
forecast-backend-vue/src/components/layout/SideMenu.vue

@@ -5,7 +5,6 @@
       :trigger="null"
       collapsible
       :class="{ 'dark-theme': layoutSettings.darkMode }"
-      :width="240"
       @collapse="$emit('update:collapsed', $event)"
   >
     <!-- Logo区域 -->

+ 28 - 6
forecast-dao/src/main/java/cn/oleauto/config/domain/ConfigWeatherLocal.java

@@ -29,16 +29,22 @@ public class ConfigWeatherLocal extends BaseEntity
     point_code:xxx
     } */
     @Excel(name = "水平面总辐照度测点配置{device_id:1, point_category:yc,point_code:xxx}")
-    private String horizontalIrradiance;
+    private String irradiance;
 
     /** 斜面辐照度测点配置 */
     @Excel(name = "斜面辐照度测点配置")
     private String irradiance;
 
+    @Excel(name = "辐照度日累计测点配置")
+    private String dailyIrradiance;
+
     /** 温度测点配置 */
     @Excel(name = "温度测点配置")
     private String temperature;
 
+    @Excel(name="组件温度测点配置")
+    private String boardTemperature;
+
     /** 气压测点配置 */
     @Excel(name = "气压测点配置")
     private String pressure;
@@ -73,14 +79,14 @@ public class ConfigWeatherLocal extends BaseEntity
     {
         return configStationId;
     }
-    public void setHorizontalIrradiance(String horizontalIrradiance) 
+    public void setIrradiance(String irradiance)
     {
-        this.horizontalIrradiance = horizontalIrradiance;
+        this.irradiance = irradiance;
     }
 
-    public String getHorizontalIrradiance() 
+    public String getIrradiance()
     {
-        return horizontalIrradiance;
+        return irradiance;
     }
     public void setIrradiance(String irradiance) 
     {
@@ -137,12 +143,28 @@ public class ConfigWeatherLocal extends BaseEntity
         return windDirection;
     }
 
+    public String getDailyIrradiance() {
+        return dailyIrradiance;
+    }
+
+    public void setDailyIrradiance(String dailyIrradiance) {
+        this.dailyIrradiance = dailyIrradiance;
+    }
+
+    public String getBoardTemperature() {
+        return boardTemperature;
+    }
+
+    public void setBoardTemperature(String boardTemperature) {
+        this.boardTemperature = boardTemperature;
+    }
+
     @Override
     public String toString() {
         return new ToStringBuilder(this,ToStringStyle.MULTI_LINE_STYLE)
             .append("id", getId())
             .append("configStationId", getConfigStationId())
-            .append("horizontalIrradiance", getHorizontalIrradiance())
+            .append("horizontalIrradiance", getIrradiance())
             .append("irradiance", getIrradiance())
             .append("temperature", getTemperature())
             .append("pressure", getPressure())

+ 39 - 11
forecast-dao/src/main/java/cn/oleauto/data/domain/DataWeatherLocal.java

@@ -27,16 +27,24 @@ public class DataWeatherLocal extends BaseEntity
 
     /** 水平面总辐照度,单位 W/m² */
     @Excel(name = "水平面总辐照度,单位 W/m²")
-    private Double horizontalIrradiance;
+    private Double irradiance;
 
     /** 斜面辐照度,单位 W/m² */
     @Excel(name = "斜面辐照度,单位 W/m²")
-    private Double irradiance;
+    private Double inclinedIrradiance;
+
+    /** 辐照度日累计,单位 MJ/m² */
+    @Excel(name = "辐照度日累计,单位 MJ/m²")
+    private Double dailyIrradiance;
 
     /** 温度,单位 ℃ */
     @Excel(name = "温度,单位 ℃")
     private Double temperature;
 
+    /** 组件温度,单位 ℃ */
+    @Excel(name = "组件温度,单位 ℃")
+    private Double boardTemperature;
+
     /** 气压,单位 hPa */
     @Excel(name = "气压,单位 hPa")
     private Double pressure;
@@ -71,23 +79,32 @@ public class DataWeatherLocal extends BaseEntity
     {
         return configStationId;
     }
-    public void setHorizontalIrradiance(Double horizontalIrradiance) 
+    public void setIrradiance(Double irradiance)
     {
-        this.horizontalIrradiance = horizontalIrradiance;
+        this.irradiance = irradiance;
     }
 
-    public Double getHorizontalIrradiance() 
+    public Double getIrradiance()
     {
-        return horizontalIrradiance;
+        return irradiance;
     }
-    public void setIrradiance(Double irradiance) 
+    public void setInclinedIrradiance(Double inclinedIrradiance) 
     {
-        this.irradiance = irradiance;
+        this.inclinedIrradiance = inclinedIrradiance;
     }
 
-    public Double getIrradiance() 
+    public Double getInclinedIrradiance() 
     {
-        return irradiance;
+        return inclinedIrradiance;
+    }
+    public void setDailyIrradiance(Double dailyIrradiance)
+    {
+        this.dailyIrradiance = dailyIrradiance;
+    }
+
+    public Double getDailyIrradiance()
+    {
+        return dailyIrradiance;
     }
     public void setTemperature(Double temperature) 
     {
@@ -98,6 +115,15 @@ public class DataWeatherLocal extends BaseEntity
     {
         return temperature;
     }
+    public void setBoardTemperature(Double boardTemperature)
+    {
+        this.boardTemperature = boardTemperature;
+    }
+
+    public Double getBoardTemperature()
+    {
+        return boardTemperature;
+    }
     public void setPressure(Double pressure) 
     {
         this.pressure = pressure;
@@ -140,9 +166,11 @@ public class DataWeatherLocal extends BaseEntity
         return new ToStringBuilder(this,ToStringStyle.MULTI_LINE_STYLE)
             .append("tm", getTm())
             .append("deviceId", getConfigStationId())
-            .append("horizontalIrradiance", getHorizontalIrradiance())
             .append("irradiance", getIrradiance())
+            .append("inclinedIrradiance", getInclinedIrradiance())
+            .append("dailyIrradiance", getDailyIrradiance())
             .append("temperature", getTemperature())
+            .append("boardTemperature", getBoardTemperature())
             .append("pressure", getPressure())
             .append("humidity", getHumidity())
             .append("windSpeed", getWindSpeed())

+ 15 - 6
forecast-dao/src/main/resources/mapper/config/ConfigWeatherLocalMapper.xml

@@ -7,9 +7,11 @@ PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
     <resultMap type="ConfigWeatherLocal" id="ConfigWeatherLocalResult">
         <result property="id"    column="id"    />
         <result property="configStationId"    column="config_station_id"    />
-        <result property="horizontalIrradiance"    column="horizontal_irradiance"    />
         <result property="irradiance"    column="irradiance"    />
+        <result property="inclinedIrradiance"    column="inclined_irradiance"    />
+        <result property="dailyIrradiance"    column="daily_irradiance"    />
         <result property="temperature"    column="temperature"    />
+        <result property="boardTemperature"    column="board_temperature"    />
         <result property="pressure"    column="pressure"    />
         <result property="humidity"    column="humidity"    />
         <result property="windSpeed"    column="wind_speed"    />
@@ -21,15 +23,16 @@ PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
     </resultMap>
 
     <sql id="selectConfigWeatherLocalVo">
-        select id, config_station_id, horizontal_irradiance, irradiance, temperature, pressure, humidity, wind_speed, wind_direction, create_time, update_time, create_by, update_by from config_weather_local
+        select id, config_station_id, irradiance, inclined_irradiance, daily_irradiance, temperature, board_temperature, pressure, humidity, wind_speed, wind_direction, create_time, update_time, create_by, update_by from config_weather_local
     </sql>
 
     <select id="selectConfigWeatherLocalList" parameterType="ConfigWeatherLocal" resultMap="ConfigWeatherLocalResult">
         <include refid="selectConfigWeatherLocalVo"/>
         <where>  
             <if test="configStationId != null  and configStationId != ''"> and config_station_id = #{configStationId}</if>
-            <if test="horizontalIrradiance != null  and horizontalIrradiance != ''"> and horizontal_irradiance = #{horizontalIrradiance}</if>
             <if test="irradiance != null  and irradiance != ''"> and irradiance = #{irradiance}</if>
+            <if test="inclinedIrradiance != null  and inclinedIrradiance != ''"> and inclined_irradiance = #{inclinedIrradiance}</if>
+            <if test="dailyIrradiance != null  and dailyIrradiance != ''"> and daily_irradiance = #{dailyIrradiance}</if>
             <if test="temperature != null  and temperature != ''"> and temperature = #{temperature}</if>
             <if test="pressure != null  and pressure != ''"> and pressure = #{pressure}</if>
             <if test="humidity != null  and humidity != ''"> and humidity = #{humidity}</if>
@@ -47,9 +50,11 @@ PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
         insert into config_weather_local
         <trim prefix="(" suffix=")" suffixOverrides=",">
             <if test="configStationId != null and configStationId != ''">config_station_id,</if>
-            <if test="horizontalIrradiance != null">horizontal_irradiance,</if>
             <if test="irradiance != null">irradiance,</if>
+            <if test="inclinedIrradiance != null">inclined_irradiance,</if>
+            <if test="dailyIrradiance != null">daily_irradiance,</if>
             <if test="temperature != null">temperature,</if>
+            <if test="boardTemperature!=null">board_emperature,</if>
             <if test="pressure != null">pressure,</if>
             <if test="humidity != null">humidity,</if>
             <if test="windSpeed != null">wind_speed,</if>
@@ -61,9 +66,11 @@ PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
          </trim>
         <trim prefix="values (" suffix=")" suffixOverrides=",">
             <if test="configStationId != null and configStationId != ''">#{configStationId},</if>
-            <if test="horizontalIrradiance != null">#{horizontalIrradiance},</if>
             <if test="irradiance != null">#{irradiance},</if>
+            <if test="inclinedIrradiance != null">#{inclinedIrradiance},</if>
+            <if test="dailyIrradiance != null">#{dailyIrradiance},</if>
             <if test="temperature != null">#{temperature},</if>
+            <if test="boardTemperature!=null">#{boardTemperature},</if>
             <if test="pressure != null">#{pressure},</if>
             <if test="humidity != null">#{humidity},</if>
             <if test="windSpeed != null">#{windSpeed},</if>
@@ -79,9 +86,11 @@ PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
         update config_weather_local
         <trim prefix="SET" suffixOverrides=",">
             <if test="configStationId != null and configStationId != ''">config_station_id = #{configStationId},</if>
-            <if test="horizontalIrradiance != null">horizontal_irradiance = #{horizontalIrradiance},</if>
             <if test="irradiance != null">irradiance = #{irradiance},</if>
+            <if test="inclinedIrradiance != null">inclined_irradiance = #{inclinedIrradiance},</if>
+            <if test="dailyIrradiance != null">daily_irradiance = #{dailyIrradiance},</if>
             <if test="temperature != null">temperature = #{temperature},</if>
+            <if test="boardTemperature != null">board_temperature = #{boardTemperature},</if>
             <if test="pressure != null">pressure = #{pressure},</if>
             <if test="humidity != null">humidity = #{humidity},</if>
             <if test="windSpeed != null">wind_speed = #{windSpeed},</if>

+ 16 - 6
forecast-dao/src/main/resources/mapper/data/DataWeatherLocalMapper.xml

@@ -7,9 +7,11 @@ PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
     <resultMap type="DataWeatherLocal" id="DataWeatherLocalResult">
         <result property="tm"    column="tm"    />
         <result property="configStationId"    column="config_station_id"    />
-        <result property="horizontalIrradiance"    column="horizontal_irradiance"    />
         <result property="irradiance"    column="irradiance"    />
+        <result property="inclinedIrradiance"    column="inclined_irradiance"    />
+        <result property="dailyIrradiance"    column="daily_irradiance"    />
         <result property="temperature"    column="temperature"    />
+        <result property="boardTemperature"    column="board_temperature"    />
         <result property="pressure"    column="pressure"    />
         <result property="humidity"    column="humidity"    />
         <result property="windSpeed"    column="wind_speed"    />
@@ -17,7 +19,7 @@ PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
     </resultMap>
 
     <sql id="selectDataWeatherLocalVo">
-        select tm, config_station_id, horizontal_irradiance, irradiance, temperature, pressure, humidity, wind_speed, wind_direction from data_weather_local
+        select tm, config_station_id, irradiance, inclined_irradiance, daily_irradiance, temperature, board_temperature, pressure, humidity, wind_speed, wind_direction from data_weather_local
     </sql>
 
     <select id="selectDataWeatherLocalList" parameterType="DataWeatherLocal" resultMap="DataWeatherLocalResult">
@@ -25,9 +27,11 @@ PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
         <where>  
             <if test="tm != null "> and tm = #{tm}</if>
             <if test="configStationId != null "> and config_station_id = #{configStationId}</if>
-            <if test="horizontalIrradiance != null "> and horizontal_irradiance = #{horizontalIrradiance}</if>
             <if test="irradiance != null "> and irradiance = #{irradiance}</if>
+            <if test="inclinedIrradiance != null "> and inclined_irradiance = #{inclinedIrradiance}</if>
+            <if test="dailyIrradiance != null "> and daily_irradiance = #{dailyIrradiance}</if>
             <if test="temperature != null "> and temperature = #{temperature}</if>
+            <if test="boardTemperature != null "> and board_temperature = #{boardTemperature}</if>
             <if test="pressure != null "> and pressure = #{pressure}</if>
             <if test="humidity != null "> and humidity = #{humidity}</if>
             <if test="windSpeed != null "> and wind_speed = #{windSpeed}</if>
@@ -45,9 +49,11 @@ PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
         <trim prefix="(" suffix=")" suffixOverrides=",">
             <if test="tm != null">tm,</if>
             <if test="configStationId != null">config_station_id,</if>
-            <if test="horizontalIrradiance != null">horizontal_irradiance,</if>
             <if test="irradiance != null">irradiance,</if>
+            <if test="inclinedIrradiance != null">inclined_irradiance,</if>
+            <if test="dailyIrradiance != null">daily_irradiance,</if>
             <if test="temperature != null">temperature,</if>
+            <if test="boardTemperature != null">board_temperature,</if>
             <if test="pressure != null">pressure,</if>
             <if test="humidity != null">humidity,</if>
             <if test="windSpeed != null">wind_speed,</if>
@@ -56,9 +62,11 @@ PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
         <trim prefix="values (" suffix=")" suffixOverrides=",">
             <if test="tm != null">#{tm},</if>
             <if test="configStationId != null">#{configStationId},</if>
-            <if test="horizontalIrradiance != null">#{horizontalIrradiance},</if>
             <if test="irradiance != null">#{irradiance},</if>
+            <if test="inclinedIrradiance != null">#{inclinedIrradiance},</if>
+            <if test="dailyIrradiance != null">#{dailyIrradiance},</if>
             <if test="temperature != null">#{temperature},</if>
+            <if test="boardTemperature != null">#{boardTemperature},</if>
             <if test="pressure != null">#{pressure},</if>
             <if test="humidity != null">#{humidity},</if>
             <if test="windSpeed != null">#{windSpeed},</if>
@@ -70,9 +78,11 @@ PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
         update data_weather_local
         <trim prefix="SET" suffixOverrides=",">
             <if test="configStationId != null">config_station_id = #{configStationId},</if>
-            <if test="horizontalIrradiance != null">horizontal_irradiance = #{horizontalIrradiance},</if>
             <if test="irradiance != null">irradiance = #{irradiance},</if>
+            <if test="inclinedIrradiance != null">inclined_irradiance = #{inclinedIrradiance},</if>
+            <if test="dailyIrradiance != null">daily_irradiance = #{dailyIrradiance},</if>
             <if test="temperature != null">temperature = #{temperature},</if>
+            <if test="boardTemperature != null">board_temperature = #{boardTemperature},</if>
             <if test="pressure != null">pressure = #{pressure},</if>
             <if test="humidity != null">humidity = #{humidity},</if>
             <if test="windSpeed != null">wind_speed = #{windSpeed},</if>

+ 0 - 2
release_note/2026.09.03/20260903_dp.sql

@@ -80,7 +80,6 @@ CREATE TABLE data_ultra_short_term_power_forecasting (
     entity_name VARCHAR(255),
     create_time INTEGER NOT NULL,
     start_time INTEGER NOT NULL,
-    forecast_time INTEGER NOT NULL,
     power VARCHAR(255),
     power15 VARCHAR(255),
     power30 VARCHAR(255),
@@ -113,7 +112,6 @@ COMMENT ON COLUMN "public"."data_ultra_short_term_power_forecasting"."entity_typ
 COMMENT ON COLUMN "public"."data_ultra_short_term_power_forecasting"."entity_name" IS '实体名称';
 COMMENT ON COLUMN "public"."data_ultra_short_term_power_forecasting"."create_time" IS '创建时间';
 COMMENT ON COLUMN "public"."data_ultra_short_term_power_forecasting"."start_time" IS '起报时间(日期)';
-COMMENT ON COLUMN "public"."data_ultra_short_term_power_forecasting"."forecast_time" IS '起报时间(日期)';
 COMMENT ON COLUMN "public"."data_ultra_short_term_power_forecasting"."power" IS '实发功率';
 COMMENT ON COLUMN "public"."data_ultra_short_term_power_forecasting"."power15" IS 't+15min预测功率';
 COMMENT ON COLUMN "public"."data_ultra_short_term_power_forecasting"."power30" IS 't+30min预测功率';

+ 0 - 6
release_note/2026.09.17/20260917_dp.sql

@@ -1,6 +0,0 @@
--- 隐藏菜单
-UPDATE "public"."sys_menu" set status = 1 where menu_name in ('多源多模型预测', '理论功率预测');
-
--- data_weather_local 斜面辐照度字段 -> 总辐照度
-ALTER TABLE "public"."data_weather_local" RENAME COLUMN "inclined_irradiance" TO "irradiance";
-COMMENT ON COLUMN "public"."data_weather_local"."irradiance" IS '总辐照度,单位 W/m²';