Quellcode durchsuchen

[10023] 风速曲线页面优化: wschart接口改为返回forecast/local时间点并集(时间升序, 缺数填0, 两侧stats等长下标对齐, 预测源同时间点多份重叠报告取首个即最新); 明细表与导出Excel均改为 时间/预测风速(m/s)/观测风速(m/s) 3列, 导出新增WsChartExportStat VO

taosj vor 5 Tagen
Ursprung
Commit
b7acdca834

+ 60 - 10
forecast-backend-server/src/main/java/com/ufo/project/forecast/shortterm/weather/controller/DataShortTermWeatherForecastRawController.java

@@ -33,6 +33,7 @@ import com.ufo.project.forecast.shortterm.weather.domain.vo.TirrChartStat;
 import com.ufo.project.forecast.shortterm.weather.domain.vo.TsfcChartExportStat;
 import com.ufo.project.forecast.shortterm.weather.domain.vo.TsfcChartResult;
 import com.ufo.project.forecast.shortterm.weather.domain.vo.TsfcChartStat;
+import com.ufo.project.forecast.shortterm.weather.domain.vo.WsChartExportStat;
 import com.ufo.project.forecast.shortterm.weather.domain.vo.WsChartResult;
 import com.ufo.project.forecast.shortterm.weather.domain.vo.WsChartStat;
 import com.ufo.project.forecast.shortterm.weather.service.IDataShortTermWeatherForecastRawService;
@@ -96,7 +97,7 @@ public class DataShortTermWeatherForecastRawController extends BaseController
     }
 
     /**
-     * 统计风速曲线数据(短期预报 + 本地实测)
+     * 统计风速曲线数据(短期预报 + 本地实测,两侧 stats 对齐到同一时间点并集,缺数填0)
      */
     @PreAuthorize("@ss.hasPermi('weather:weatherRaw:wschart')")
     @GetMapping("/wschart")
@@ -105,11 +106,12 @@ public class DataShortTermWeatherForecastRawController extends BaseController
     {
         WsChartResult forecast = dataShortTermWeatherForecastRawService.getWsChart(stationId, startTime, endTime);
         WsChartResult local = dataWeatherLocalService.getWsChart(stationId, startTime, endTime);
+        alignWsStats(forecast, local);
         return success(new ChartDataPair<WsChartResult>(forecast, local));
     }
 
     /**
-     * 导出风速曲线数据(短期预报 + 本地实测,合并导出)
+     * 导出风速曲线数据(短期预报 + 本地实测,按时间点并集对齐导出 时间/预测风速/观测风速)
      */
     @PreAuthorize("@ss.hasPermi('weather:weatherRaw:wschart')")
     @Log(title = "风速曲线", businessType = BusinessType.EXPORT)
@@ -119,16 +121,16 @@ public class DataShortTermWeatherForecastRawController extends BaseController
     {
         WsChartResult forecast = dataShortTermWeatherForecastRawService.getWsChart(stationId, startTime, endTime);
         WsChartResult local = dataWeatherLocalService.getWsChart(stationId, startTime, endTime);
-        List<WsChartStat> stats = new ArrayList<WsChartStat>();
-        if (forecast.getStats() != null)
+        alignWsStats(forecast, local);
+        List<WsChartStat> forecastStats = forecast.getStats();
+        List<WsChartStat> localStats = local.getStats();
+        List<WsChartExportStat> stats = new ArrayList<WsChartExportStat>();
+        for (int i = 0; i < forecastStats.size(); i++)
         {
-            stats.addAll(forecast.getStats());
+            stats.add(new WsChartExportStat(forecastStats.get(i).getTime(),
+                    forecastStats.get(i).getWs(), localStats.get(i).getWs()));
         }
-        if (local.getStats() != null)
-        {
-            stats.addAll(local.getStats());
-        }
-        ExcelUtil<WsChartStat> util = new ExcelUtil<WsChartStat>(WsChartStat.class);
+        ExcelUtil<WsChartExportStat> util = new ExcelUtil<WsChartExportStat>(WsChartExportStat.class);
         util.exportExcel(response, stats, "风速曲线数据");
     }
 
@@ -378,6 +380,54 @@ public class DataShortTermWeatherForecastRawController extends BaseController
         return map;
     }
 
+    /**
+     * 将风速曲线的短期预报与本地实测对齐到同一时间点并集(时间从小到大)。
+     * 某侧缺失的时间点 ws 填 0;预测源同一时间点可能含多份重叠报告,保留列表中首个(最新报告)。
+     * 合并后两侧 stats 等长、下标一一对应。
+     */
+    private void alignWsStats(WsChartResult forecast, WsChartResult local)
+    {
+        Map<String, Double> forecastMap = buildWsTimeMap(forecast.getStats());
+        Map<String, Double> localMap = buildWsTimeMap(local.getStats());
+        TreeSet<String> times = new TreeSet<String>();
+        times.addAll(forecastMap.keySet());
+        times.addAll(localMap.keySet());
+        List<WsChartStat> forecastStats = new ArrayList<WsChartStat>();
+        List<WsChartStat> localStats = new ArrayList<WsChartStat>();
+        for (String time : times)
+        {
+            WsChartStat forecastStat = new WsChartStat(time, forecastMap.getOrDefault(time, 0d));
+            forecastStat.setSource("预测");
+            forecastStats.add(forecastStat);
+            WsChartStat localStat = new WsChartStat(time, localMap.getOrDefault(time, 0d));
+            localStat.setSource("本地实测");
+            localStats.add(localStat);
+        }
+        forecast.setStats(forecastStats);
+        local.setStats(localStats);
+    }
+
+    /**
+     * 按时间建立 时间->风速 映射(LinkedHashMap 保留列表序,putIfAbsent 去重取首个)
+     */
+    private Map<String, Double> buildWsTimeMap(List<WsChartStat> stats)
+    {
+        Map<String, Double> map = new LinkedHashMap<String, Double>();
+        if (stats == null)
+        {
+            return map;
+        }
+        for (WsChartStat stat : stats)
+        {
+            if (stat == null || stat.getTime() == null)
+            {
+                continue;
+            }
+            map.putIfAbsent(stat.getTime(), stat.getWs() == null ? 0d : stat.getWs());
+        }
+        return map;
+    }
+
     /**
      * 导出短期气象原始数据列表
      */

+ 65 - 0
forecast-backend-server/src/main/java/com/ufo/project/forecast/shortterm/weather/domain/vo/WsChartExportStat.java

@@ -0,0 +1,65 @@
+package com.ufo.project.forecast.shortterm.weather.domain.vo;
+
+import com.ufo.base.framework.aspectj.lang.annotation.Excel;
+
+/**
+ * 风速曲线导出行数据(预测与本地实测按时间点并集对齐,缺数填0)
+ *
+ * @author ufo
+ * @date 2026-10-29
+ */
+public class WsChartExportStat
+{
+    /** 时间(yyyy-MM-dd HH:mm:ss) */
+    @Excel(name = "时间")
+    private String time;
+
+    /** 预测风速(m/s) */
+    @Excel(name = "预测风速(m/s)")
+    private Double forecastWs;
+
+    /** 观测风速(m/s) */
+    @Excel(name = "观测风速(m/s)")
+    private Double localWs;
+
+    public WsChartExportStat()
+    {
+    }
+
+    public WsChartExportStat(String time, Double forecastWs, Double localWs)
+    {
+        this.time = time;
+        this.forecastWs = forecastWs;
+        this.localWs = localWs;
+    }
+
+    public String getTime()
+    {
+        return time;
+    }
+
+    public void setTime(String time)
+    {
+        this.time = time;
+    }
+
+    public Double getForecastWs()
+    {
+        return forecastWs;
+    }
+
+    public void setForecastWs(Double forecastWs)
+    {
+        this.forecastWs = forecastWs;
+    }
+
+    public Double getLocalWs()
+    {
+        return localWs;
+    }
+
+    public void setLocalWs(Double localWs)
+    {
+        this.localWs = localWs;
+    }
+}

+ 12 - 16
forecast-backend-vue/src/views/ufo/electricity/weather/WindSpeedCurve.vue

@@ -84,8 +84,8 @@ const hasData = computed(() => !!summary.value && (summary.value.totalRecords >
 
 const columns = [
   {title: '时间', dataIndex: 'time', width: 180, align: 'center', fixed: 'left'},
-  {title: '来源', dataIndex: 'source', width: 100, align: 'center'},
-  {title: '风速(m/s)', dataIndex: 'ws', width: 150, align: 'right'}
+  {title: '预测风速(m/s)', dataIndex: 'forecastWs', width: 150, align: 'right'},
+  {title: '观测风速(m/s)', dataIndex: 'localWs', width: 150, align: 'right'}
 ];
 
 const pagination = {
@@ -191,20 +191,16 @@ const handleQuery = async () => {
       localTotalRecords: local.totalRecords || 0,
       localValidRecords: local.validRecords || 0
     };
-    detailRows.value = [
-      ...(forecast.stats || []).map((item, index) => ({
-        key: `forecast-${index}`,
-        time: item.time,
-        source: item.source || '预测',
-        ws: toNumber(item.ws, 0)
-      })),
-      ...(local.stats || []).map((item, index) => ({
-        key: `local-${index}`,
-        time: item.time,
-        source: item.source || '观测',
-        ws: toNumber(item.ws, 0)
-      }))
-    ];
+    // 后端已将 forecast/local 的 stats 对齐到同一时间点并集(缺数填0),按下标对齐取行
+    const forecastStats = forecast.stats || [];
+    const localStats = local.stats || [];
+    const rowCount = Math.max(forecastStats.length, localStats.length);
+    detailRows.value = Array.from({ length: rowCount }, (_, index) => ({
+      key: `row-${index}`,
+      time: forecastStats[index]?.time || localStats[index]?.time,
+      forecastWs: toNumber(forecastStats[index]?.ws, 0),
+      localWs: toNumber(localStats[index]?.ws, 0)
+    }));
     renderChart(forecast.stats || [], local.stats || []);
   } finally {
     loading.value = false;