2 Commits e74b43126c ... 6f67c16347

Autore SHA1 Messaggio Data
  wangb 6f67c16347 Merge branch 'master' of http://124.70.43.205:3000/wangb/runeconomy-nx 1 settimana fa
  wangb 1fa70ed194 功率曲线拟合 1 settimana fa
26 ha cambiato i file con 2192 aggiunte e 34 eliminazioni
  1. 17 0
      data-adapter/src/main/java/com/gyee/dataadapter/controller/AdapterController.java
  2. 1 1
      data-adapter/src/main/java/com/gyee/dataadapter/dao_mqtt_influxdb_taos/TaosDataService.java
  3. 2 0
      data-adapter/src/main/java/com/gyee/dataadapter/service/IAdapterService.java
  4. 6 1
      data-adapter/src/main/java/com/gyee/dataadapter/service/TsDataService.java
  5. 13 4
      data-adapter/src/main/java/com/gyee/dataadapter/service/impl/AdapterServiceImpl.java
  6. 3 0
      runeconomy-xk/src/main/java/com/gyee/runeconomy/config/GyeeConfig.java
  7. 15 15
      runeconomy-xk/src/main/java/com/gyee/runeconomy/controller/NewDataFittingController.java
  8. 3 3
      runeconomy-xk/src/main/java/com/gyee/runeconomy/dto/result/PowerPointData.java
  9. 47 0
      runeconomy-xk/src/main/java/com/gyee/runeconomy/init/CacheContext.java
  10. 17 0
      runeconomy-xk/src/main/java/com/gyee/runeconomy/mapper/auto/ProEconPowerFittingAnalySisMapper.java
  11. 36 0
      runeconomy-xk/src/main/java/com/gyee/runeconomy/model/LineCurveFitting.java
  12. 322 0
      runeconomy-xk/src/main/java/com/gyee/runeconomy/model/PowerFittingALG.java
  13. 36 0
      runeconomy-xk/src/main/java/com/gyee/runeconomy/model/PowerFittingData.java
  14. 375 0
      runeconomy-xk/src/main/java/com/gyee/runeconomy/model/PowerProcessALG.java
  15. 3 0
      runeconomy-xk/src/main/java/com/gyee/runeconomy/model/auto/ProEconPowerFittingAnalySis.java
  16. 3 1
      runeconomy-xk/src/main/java/com/gyee/runeconomy/model/auto/TurbineInfoDay.java
  17. 3 3
      runeconomy-xk/src/main/java/com/gyee/runeconomy/model/vo/ComparetqVo.java
  18. 3 3
      runeconomy-xk/src/main/java/com/gyee/runeconomy/model/vo/GeneratingCapacityVo.java
  19. 8 3
      runeconomy-xk/src/main/java/com/gyee/runeconomy/model/vo/PointVo.java
  20. 58 0
      runeconomy-xk/src/main/java/com/gyee/runeconomy/service/DBSCANPointALG.java
  21. 25 0
      runeconomy-xk/src/main/java/com/gyee/runeconomy/service/DataScanService.java
  22. 600 0
      runeconomy-xk/src/main/java/com/gyee/runeconomy/service/auto/impl/NewDataFittingService.java
  23. 41 0
      runeconomy-xk/src/main/java/com/gyee/runeconomy/service/auto/impl/ProEconPowerFittingAnalySisService.java
  24. 105 0
      runeconomy-xk/src/main/java/com/gyee/runeconomy/service/auto/impl/ProEconPowerFittingAnalySisServiceImpl.java
  25. 288 0
      runeconomy-xk/src/main/java/com/gyee/runeconomy/util/FileUtil.java
  26. 162 0
      runeconomy-xk/src/main/java/com/gyee/runeconomy/util/SnowFlakeUtil.java

+ 17 - 0
data-adapter/src/main/java/com/gyee/dataadapter/controller/AdapterController.java

@@ -1,5 +1,6 @@
 package com.gyee.dataadapter.controller;
 
+import com.alibaba.druid.sql.visitor.functions.If;
 import com.gyee.dataadapter.entity.DoubleStatData;
 import com.gyee.dataadapter.entity.PointData;
 import com.gyee.dataadapter.entity.PointInfo;
@@ -62,6 +63,22 @@ public class AdapterController {
         return tsDataService.getHistorySnap(tagName, startTs, endTs, interval);
     }
 
+    @GetMapping("/history/statso")
+    public PointData getHistoryStat5(@RequestParam("tagName") String tagName,
+                                           @RequestParam("startTs") Long startTs, @RequestParam("endTs") Long endTs,
+                                           @RequestParam(value = "type", required = false) Integer type) {
+        List<PointData> stat = tsDataService.getHistoryStat2(tagName, new Date(startTs), new Date(endTs), type);
+        return stat.get(0);
+    }
+
+    @GetMapping("/history/stats")
+    public List<PointData> getHistoryStat4(@RequestParam("tagName") String tagName,
+                                           @RequestParam("startTs") Long startTs, @RequestParam("endTs") Long endTs,
+                                           @RequestParam(value = "interval", required = false) Integer interval,
+                                           @RequestParam(value = "type", required = false) Integer type) {
+        return tsDataService.getHistoryStat(tagName, new Date(startTs), new Date(endTs), interval, type);
+    }
+
     @GetMapping("/history/stat3")
     public List<PointData> getHistoryStat3(@RequestParam("tagName") String tagName,
                                           @RequestParam("startTs") Long startTs,

+ 1 - 1
data-adapter/src/main/java/com/gyee/dataadapter/dao_mqtt_influxdb_taos/TaosDataService.java

@@ -57,7 +57,7 @@ public class TaosDataService implements IHistoryDao {
 
     private String getHistorySnapSql(String tagName, long startTs, long endTs, Integer interval) {
         StringBuilder sb = new StringBuilder();
-        sb.append("select interp(val,1) from ").append(config.getDbName()).append(".").append(tagName.toLowerCase())
+        sb.append("select _irowts,interp(val,1) from ").append(config.getDbName()).append(".").append(tagName.toLowerCase())
                 .append(" range(").append(startTs).append(",").append(endTs).append(") every(")
                 .append(interval).append("s) fill(prev)");
         return sb.toString();

+ 2 - 0
data-adapter/src/main/java/com/gyee/dataadapter/service/IAdapterService.java

@@ -23,6 +23,8 @@ public interface IAdapterService {
     TotalPointData getTotalData(Date start, Date end, Integer sampleType, String paths);
 
     List<PointData> getPointData(Date start, Date end, Integer sampleType, Integer sampleRate, String paths);
+    List<PointData> getPointData(Date start, Date end, Integer sampleType, Integer sampleRate, String paths,
+                                String pageIndex, String pageSize, Boolean isDesc);
 
     List<PointData> getPointData2(Date start, Date end, Integer sampleType, String paths);
 

+ 6 - 1
data-adapter/src/main/java/com/gyee/dataadapter/service/TsDataService.java

@@ -1,6 +1,8 @@
 package com.gyee.dataadapter.service;
 
 import cn.hutool.core.collection.CollUtil;
+import cn.hutool.core.date.DateTime;
+import cn.hutool.core.date.DateUtil;
 import com.gyee.dataadapter.dao.IHistoryDao;
 import com.gyee.dataadapter.dao.ILatestDao;
 import com.gyee.dataadapter.entity.PointData;
@@ -154,7 +156,10 @@ public class TsDataService {
             List<String> strings = nxFgs.get(false);
             if (CollUtil.isEmpty(strings)) return result;
             for (String tagName : strings) {
-                List<PointData> pdsMap = adapterService.getPointData(time, time, 1, null, tagName);
+                //Date start, Date end, Integer sampleType, Integer sampleRate, String paths,
+                //                                String pageIndex, String pageSize, Boolean isDesc
+                DateTime time0 = DateUtil.offsetDay(time, -3);
+                List<PointData> pdsMap = adapterService.getPointData(time0, time, 1, 0, tagName,"1","1",true);
                 if (CollUtil.isNotEmpty(pdsMap)) result.put(tagName, pdsMap.get(0));
             }
             return result;

File diff suppressed because it is too large
+ 13 - 4
data-adapter/src/main/java/com/gyee/dataadapter/service/impl/AdapterServiceImpl.java


+ 3 - 0
runeconomy-xk/src/main/java/com/gyee/runeconomy/config/GyeeConfig.java

@@ -40,14 +40,17 @@ public class GyeeConfig {
     /**
      * 数据准备保存路径(原始数据)
      **/
+    @Value("${powerCurveFitting.prepare}")
     private String filePathPrepare;
     /**
      * 数据处理保存路径(处理后的数据)
      **/
+    @Value("${powerCurveFitting.process}")
     private String filePathProcess;
     /**
      * 数据拟合保存路径(拟合后的数据)
      **/
+    @Value("${powerCurveFitting.fitting}")
     private String filePathFitting;
     /**
      * 数据压缩下载

+ 15 - 15
runeconomy-xk/src/main/java/com/gyee/runeconomy/controller/NewDataFittingController.java

@@ -42,11 +42,11 @@ public class NewDataFittingController {
      * @param id  拟合好的数据ID
      * @return
      */
-//    @GetMapping("curve")
-//    public JSONObject dataFittingCurve(String id){
-//        Map<String, Object> result = newDataFittingService.dataFittingCurve(id);
-//        return JsonResult.successData(ResultCode.SUCCESS, result);
-//    }
+    @GetMapping("curve")
+    public JSONObject dataFittingCurve(String id){
+        Map<String, Object> result = newDataFittingService.dataFittingCurve(id);
+        return JsonResult.successData(ResultCode.SUCCESS, result);
+    }
 
 
 
@@ -57,11 +57,11 @@ public class NewDataFittingController {
      * @param wk  无用点的key
      * @return
      */
-//    @GetMapping("filter")
-//    public JSONObject dataFittingFilter(String yk, String wk){
-//        List<PowerPointData> list = newDataFittingService.dataOrigin(yk, wk);
-//        return JsonResult.successData(ResultCode.SUCCESS, list);
-//    }
+    @GetMapping("filter")
+    public JSONObject dataFittingFilter(String yk, String wk){
+        List<PowerPointData> list = newDataFittingService.dataOrigin(yk, wk);
+        return JsonResult.successData(ResultCode.SUCCESS, list);
+    }
 
 
     /**
@@ -69,10 +69,10 @@ public class NewDataFittingController {
      * @param id
      * @return
      */
-//    @GetMapping("show")
-//    public JSONObject dataFittingShow(String id){
-//        Map<String, Object> result = newDataFittingService.dataFittingShow(id);
-//        return JsonResult.successData(ResultCode.SUCCESS, result);
-//    }
+    @GetMapping("/show")
+    public JSONObject dataFittingShow(String id){
+        Map<String, Object> result = newDataFittingService.dataFittingShow(id);
+        return JsonResult.successData(ResultCode.SUCCESS, result);
+    }
 
 }

+ 3 - 3
runeconomy-xk/src/main/java/com/gyee/runeconomy/dto/result/PowerPointData.java

@@ -99,8 +99,8 @@ public class PowerPointData {
     @Desc(des = "叶片3",  uniformCode = "AI084", remark = "1")
     private double yp3 = 0;
 
-    //是否过滤  0:不过滤 1:过滤
-    @Desc(des = "筛选", uniformCode = "筛选",remark = "0")
+//    是否过滤  0:不过滤 1:过滤
+    @Desc(des = "筛选", remark = "0")
     private int filter = 0;
 
     private String wtId;
@@ -119,7 +119,7 @@ public class PowerPointData {
                 ", dfwc=" + dfwc +
                 ", angle=" + angle +
                 ", hjwd=" + hjwd +
-                ", filter=" + filter +
+//                ", filter=" + filter +
                 ", wtId='" + wtId + '\'' +
                 '}';
     }

+ 47 - 0
runeconomy-xk/src/main/java/com/gyee/runeconomy/init/CacheContext.java

@@ -16,6 +16,9 @@ import org.springframework.boot.CommandLineRunner;
 import org.springframework.stereotype.Component;
 
 import javax.annotation.Resource;
+import java.math.BigDecimal;
+import java.time.LocalDate;
+import java.time.temporal.TemporalAdjusters;
 import java.util.*;
 import java.util.stream.Collectors;
 
@@ -86,6 +89,9 @@ public class CacheContext implements CommandLineRunner {
     private ITemperatureinfoService iTemperatureinfoService;
 
     @Resource
+    private ITurbineInfoDayService iTurbineInfoDayService;
+
+    @Resource
     GyeeConfig config;
 
 
@@ -181,6 +187,13 @@ public class CacheContext implements CommandLineRunner {
 
     public static Map<String, List<ProBasicEquipmentPoint>> pointNewMap = new HashMap<>();
 
+    public static Map<String, List<ProBasicModelPower>> modelPowerDetailNewMap = new HashMap<>();
+
+    public static BigDecimal yfdl = null;
+    public static BigDecimal yllfdl = null;
+    public static BigDecimal nfdl = null;
+    public static BigDecimal nllfdl = null;
+
 
     @Override
     public void run(String... args) throws Exception {
@@ -672,13 +685,47 @@ public class CacheContext implements CommandLineRunner {
         statusMap = JSONObject.parseObject(sszzt, new TypeReference<Map<String, List<ProBasicStatusPoint>>>() {
         });
 
+        cacheNewModelPower();
         cacheNewPoints();
         initTemperatureInfo();
+        cacheYNfdl();
 
         logger.info("缓存结束------------------------------------------------------------");
     }
 
 
+    private void cacheYNfdl() {
+        LocalDate currentDate = LocalDate.now(); // 获取当前日期
+        int year = currentDate.getYear(); // 获取年份
+        int month = currentDate.getMonthValue();
+        QueryWrapper<TurbineInfoDay> currentqw = new QueryWrapper<>();
+        currentqw.select("station_id,MAX(record_date) AS record_date,SUM(rfdl) AS rfdl,sum(llfdl) as llfdl")
+                .apply("to_char(record_date,'yyyy-MM') = {0}",year + "-" + String.format("%02d",month))
+                .like("station_id","_FDC_")
+                .groupBy("to_char(record_date,'yyyy-MM'),station_id");
+        List<TurbineInfoDay> monthData = iTurbineInfoDayService.list(currentqw);
+        yfdl = monthData.get(0).getRfdl();
+        yllfdl = monthData.get(0).getLlfdl();
+        currentqw.clear();
+        currentqw.select("station_id,MAX(record_date) AS record_date,SUM(rfdl) AS rfdl,sum(llfdl) as llfdl")
+                .ge("record_date",LocalDate.now().with(TemporalAdjusters.firstDayOfMonth()).minusMonths(1)) // 大于等于上个月的第一天
+                .lt("record_date",LocalDate.now().with(TemporalAdjusters.firstDayOfMonth())) // 小于本月的第一天
+                .like("station_id","_FDC_%") // 模糊查询 station_id
+                .groupBy("station_id");
+        List<TurbineInfoDay> yearData = iTurbineInfoDayService.list(currentqw);
+        nfdl = yearData.get(0).getRfdl();
+        nllfdl = yearData.get(0).getLlfdl();
+        System.out.println();
+//        stations.forEach(s->);
+    }
+
+
+    private void cacheNewModelPower() {
+        List<ProBasicModelPower> lsMPD = proBasicModelPowerService.list();
+        modelPowerDetailNewMap.putAll(lsMPD.stream().collect(Collectors.groupingBy(u -> u.getModelId())));
+        System.out.println("保证功率数据缓存完成");
+    }
+
     private void cacheNewPoints() {
         List<ProBasicEquipmentPoint> list = new ArrayList<>();
         wpls.stream().forEach(d -> list.addAll(proBasicEquipmentPointService.selectList(d.getId(), config.getPoints())));

+ 17 - 0
runeconomy-xk/src/main/java/com/gyee/runeconomy/mapper/auto/ProEconPowerFittingAnalySisMapper.java

@@ -0,0 +1,17 @@
+package com.gyee.runeconomy.mapper.auto;
+
+
+import com.baomidou.mybatisplus.core.mapper.BaseMapper;
+import com.gyee.runeconomy.model.auto.ProEconPowerFittingAnalySis;
+
+/**
+ * <p>
+ *  Mapper 接口
+ * </p>
+ *
+ * @author chenmh
+ * @since 2023-09-24
+ */
+public interface ProEconPowerFittingAnalySisMapper extends BaseMapper<ProEconPowerFittingAnalySis> {
+
+}

+ 36 - 0
runeconomy-xk/src/main/java/com/gyee/runeconomy/model/LineCurveFitting.java

@@ -0,0 +1,36 @@
+package com.gyee.runeconomy.model;
+
+import com.gyee.runeconomy.service.WindDirection.Point;
+import lombok.Data;
+
+import java.util.List;
+
+@Data
+public class LineCurveFitting {
+
+    public String name;
+    public List<Point> lines;
+    public List<Point> YLines;
+
+    public List<Point> point;
+    public List<Point> YPoint;
+
+    /// <summary>
+    /// 推力系数
+    /// </summary>
+    public List<Point> CpValue;
+    /// <summary>
+    /// 推力系数平均值
+    /// </summary>
+    public double CpAvg;
+    /// <summary>
+    /// 平均风速
+    /// </summary>
+    public double speed;
+
+    /// <summary>
+    /// 静风频率
+    /// </summary>
+    public double frequency;
+
+}

+ 322 - 0
runeconomy-xk/src/main/java/com/gyee/runeconomy/model/PowerFittingALG.java

@@ -0,0 +1,322 @@
+package com.gyee.runeconomy.model;
+
+import com.gyee.runeconomy.service.WindDirection.Point;
+
+import java.math.BigDecimal;
+import java.util.*;
+
+/**
+ * 功率曲线拟合算法
+ * 最小二乘法
+ */
+public class PowerFittingALG {
+
+    /**
+     * 功率曲线拟合
+     *
+     * @param arrX        风速数组
+     * @param arrY        功率数据
+     * @param length      点个数
+     * @param dimension   维度
+     * @param scale       精度  0.1  0.01
+     * @return
+     */
+    public static List<Point> buildLine(double[] arrX, double[] arrY, int length, int dimension, double scale) {
+
+        List<Point> points = new ArrayList<>();
+
+        if (arrX.length != arrY.length || arrX.length < 3) {
+            return points;
+        }
+
+        double minValue = arrY[0];
+        double maxValue = arrY[arrY.length - 1];
+
+        double min = 0;
+        double max = 0;
+
+        double[] coefficient = MultiLine(arrX, arrY, length, dimension);
+
+        for (double i = arrX[0]; i <= arrX[arrX.length - 1]; i += scale) {
+            Point point = new Point();
+            point.setX(i);
+
+
+            for (int j = 0; j < coefficient.length; j++) {
+                if (j == 0) {
+                    point.setY(coefficient[j] * Math.pow(point.getX(), j));
+                } else {
+                    double temp = coefficient[j] * Math.pow(point.getX(), j);
+                    point.setY(point.getY() + temp);
+                }
+
+            }
+            if (point.getY() < minValue) {
+                point.setY(minValue);
+
+            }
+            if (point.getY() > maxValue) {
+                point.setY(maxValue);
+            }
+
+            if (point.getY() < min) {
+                min = point.getY();
+            }
+            if (point.getY() > max) {
+                max = point.getY();
+            }
+
+            points.add(point);
+        }
+        Builder(points, min, max);
+        return points;
+    }
+
+    private static void Builder(List<Point> points, double min, double max) {
+        boolean b = false;
+        for (int i = 0; i < points.size(); i++) {
+            if (b) {
+                points.get(i).setY(max);
+            } else {
+                if (max == points.get(i).getY()) {
+                    b = true;
+                }
+            }
+
+        }
+
+        for (int i = points.size() - 1; i > -1; i--) {
+            if (!b) {
+                points.get(i).setY(min);
+            } else {
+                if (min == points.get(i).getY()) {
+                    b = false;
+                }
+            }
+
+        }
+    }
+
+
+    ///<summary>
+    ///用最小二乘法拟合二元多次曲线
+    ///</summary>
+    ///<param name="arrX">已知点的x坐标集合</param>
+    ///<param name="arrY">已知点的y坐标集合</param>
+    ///<param name="length">已知点的个数</param>
+    ///<param name="dimension">方程的最高次数</param>
+    //二元多次线性方程拟合曲线
+    private static double[] MultiLine(double[] arrX, double[] arrY, int length, int dimension) {
+        int n = dimension + 1;                  //dimension次方程需要求 dimension+1个 系数
+        double[][] Guass = new double[n][n + 1];      //高斯矩阵 例如:y=a0+a1*x+a2*x*x
+        for (int i = 0; i < n; i++) {
+            int j;
+            for (j = 0; j < n; j++) {
+                Guass[i][j] = SumArr(arrX, j + i, length);
+            }
+            Guass[i][j] = SumArr(arrX, i, arrY, 1, length);
+        }
+        return ComputGauss(Guass, n);
+    }
+
+    //求数组的元素的n次方的和
+    private static double SumArr(double[] arr, int n, int length) {
+        double s = 0;
+        for (int i = 0; i < length; i++) {
+            if (arr[i] != 0 || n != 0)
+                s = s + Math.pow(arr[i], n);
+            else
+                s = s + 1;
+        }
+        return s;
+    }
+
+    private static double SumArr(double[] arr1, int n1, double[] arr2, int n2, int length) {
+        double s = 0;
+        for (int i = 0; i < length; i++) {
+            if ((arr1[i] != 0 || n1 != 0) && (arr2[i] != 0 || n2 != 0))
+                s = s + Math.pow(arr1[i], n1) * Math.pow(arr2[i], n2);
+            else
+                s = s + 1;
+        }
+        return s;
+
+    }
+
+    private static double[] ComputGauss(double[][] Guass, int n) {
+        int i, j;
+        int k, m;
+        double temp;
+        double max;
+        double s;
+        double[] x = new double[n];
+        for (i = 0; i < n; i++) x[i] = 0.0;//初始化
+
+        for (j = 0; j < n; j++) {
+            max = 0;
+            k = j;
+            for (i = j; i < n; i++) {
+                if (Math.abs(Guass[i][j]) > max) {
+                    max = Guass[i][j];
+                    k = i;
+                }
+            }
+
+
+            if (k != j) {
+                for (m = j; m < n + 1; m++) {
+                    temp = Guass[j][m];
+                    Guass[j][m] = Guass[k][m];
+                    Guass[k][m] = temp;
+                }
+            }
+            if (0 == max) {
+                // "此线性方程为奇异线性方程" 
+                return x;
+            }
+
+            for (i = j + 1; i < n; i++) {
+                s = Guass[i][j];
+                for (m = j; m < n + 1; m++) {
+                    Guass[i][m] = Guass[i][m] - Guass[j][m] * s / (Guass[j][j]);
+                }
+            }
+
+        }//结束for (j=0;j<n;j++)
+
+        for (i = n - 1; i >= 0; i--) {
+            s = 0;
+            for (j = i + 1; j < n; j++) {
+                s = s + Guass[i][j] * x[j];
+            }
+            x[i] = (Guass[i][n] - s) / Guass[i][i];
+        }
+        return x;
+    }//返回值是函数的系数
+
+
+    /**
+     * 推力系数 CP 值
+     * @param sweptarea  扫风面积
+     * @param line
+     * @return
+     */
+    public static LineCurveFitting buildCp(Double sweptarea, LineCurveFitting line){
+        List<Point> cpValue = new ArrayList<>();
+
+        double kqmd = 1.225; //空气密度
+        double max = 0;
+        double cpAvg = 0;
+        double sum1 = 0;
+
+        for (int i = 0; i < line.getYLines().size(); i++)
+        {
+            Point point = line.getYLines().get(i);
+            double speed = point.getX();
+            double power = point.getY();
+            double k = 0.5 * kqmd * Math.pow(speed, 3) * sweptarea;
+            double result = 0;
+            if (k != 0)
+                result = power / k * 1000;
+            //s5.Points.AddXY(speed, result);
+            Point cppoint = new Point();
+            cppoint.setX(speed);
+            cppoint.setY(result);
+            cpValue.add(cppoint);
+
+            if (max < result)
+            {
+                max = result;
+            }
+
+            if (result > 0 && speed >= 3 && speed <= 25)
+            {
+                cpAvg += result;
+                sum1++;
+
+            }
+
+        }
+        if(sum1>0)
+            cpAvg /= sum1;
+
+        line.setCpValue(cpValue);
+        line.setCpAvg(new BigDecimal(cpAvg).setScale(2, BigDecimal.ROUND_CEILING).doubleValue());
+
+        return line;
+    }
+
+
+
+
+
+    /**
+     * 曲线偏差率
+     * @param points1 风速功率数组
+     * @param points2
+     * @param maxp
+     * @return
+     */
+    public static double curveDeviationRatio(List<Point> points1, List<Point> points2, double maxp) {
+        double result = -0;
+        double pc = 0;
+        if (points1 != null && points1.size() > 0 && points2 != null && points2.size() > 0)
+        {
+            double count = 0;
+            double sum = 0;
+            for (Point point : points1){
+                Optional<Point> p = points2.stream().filter(it -> it.getX() == point.getX()).findFirst();
+                if (p.isPresent()){
+                    sum += Math.pow(point.getY() - p.get().getY(), 2);
+                    count ++;
+                    pc += point.getY() - p.get().getY();
+                }
+            }
+            sum = Math.sqrt(sum);
+            count = Math.sqrt(count);
+            maxp = maxp * count;
+            if (maxp != 0)
+                result = sum / maxp * 100;
+            if (pc < 0)
+                result = 0 - result;
+        }
+        return result;
+    }
+
+    /**
+     * 曲线偏差率  正负偏差
+     * @param points1 风速功率数组
+     * @param points2 风速功率数组(保证功率)
+     * @param maxp  区间内的最大保证功率
+     * @param mins 最小风速
+     * @param maxs 最大风速
+     * @return
+     */
+    public static double curveDeviationRatio2(List<Point> points1, List<Point> points2, double maxp, double mins, double maxs) {
+        double result = -0;
+        double pc = 0;
+        if (points1 != null && points1.size() > 0 && points2 != null && points2.size() > 0)
+        {
+            double count = 0;
+            double sum = 0;
+            for (Point point : points1){
+                Optional<Point> p = points2.stream().filter(it -> it.getX() == point.getX()).findFirst();
+                if (p.isPresent() && p.get().getX() >= mins && p.get().getX() < maxs){
+                    sum += Math.pow(point.getY() - p.get().getY(), 2);
+                    count ++;
+                    pc += point.getY() - p.get().getY();
+                }
+            }
+            sum = Math.sqrt(sum);
+            count = Math.sqrt(count);
+            maxp = maxp * count;
+            if (maxp != 0)
+                result = sum / maxp * 100;
+            if (pc < 0)
+                result = 0 - result;
+        }
+        return result;
+    }
+
+}
+

+ 36 - 0
runeconomy-xk/src/main/java/com/gyee/runeconomy/model/PowerFittingData.java

@@ -0,0 +1,36 @@
+package com.gyee.runeconomy.model;
+
+import com.gyee.runeconomy.dto.speed.Desc;
+import lombok.Data;
+
+/**
+ * 拟合后对应的曲线 model
+ */
+@Data
+public class PowerFittingData {
+
+    public PowerFittingData(){}
+
+    public PowerFittingData(String[] str) {
+        if (str.length >= 2){
+            this.speed = Double.valueOf(str[0]);
+            this.nhdata = Double.valueOf(str[1]);
+            this.cpdata = ((double)((int)(Double.valueOf(str[2])*1000)))/1000;
+        }
+    }
+
+
+    //风速
+    @Desc(des = "风速", remark = "1")
+    private Double speed;
+    //拟合功率
+    @Desc(des = "拟合功率", remark = "1")
+    private Double nhdata;
+    //修正数据
+    @Desc(des = "修正功率", remark = "0")
+    private Double xzdata;
+    //cp值
+    @Desc(des = "Cp值", remark = "1")
+    private Double cpdata;
+
+}

+ 375 - 0
runeconomy-xk/src/main/java/com/gyee/runeconomy/model/PowerProcessALG.java

@@ -0,0 +1,375 @@
+package com.gyee.runeconomy.model;
+
+
+import cn.hutool.core.date.DateUtil;
+import com.gyee.runeconomy.dto.result.PowerPointData;
+
+import java.text.ParseException;
+import java.text.SimpleDateFormat;
+import java.util.ArrayList;
+import java.util.Date;
+import java.util.List;
+import java.util.Map;
+
+/**
+ * 数据预处理算法
+ */
+public class PowerProcessALG {
+
+
+    public final static String DATE_TIME_PATTERN = "yyyy-MM-dd HH:mm:ss";
+
+
+    /**
+     * 数据预处理
+     *
+     * @param list   预处理的数据
+     * @param map    风速对应的保证功率
+     * @param maxs   最大风速
+     * @param mins   最小风速
+     * @param maxp   最大功率
+     * @param minp   最小功率
+     * @param isfbw  是否并网
+     * @param isfhl  是否合理值
+     * @param isbw   并网后10分钟
+     * @param istj   停机前10分钟
+     * @param isglpc 功率曲线偏差
+     * @param isqfh  是否欠符合
+     * @param qfhdj  欠符合等级
+     * @return
+     */
+    public static List<PowerPointData> dataProcess(List<PowerPointData> list, Map<Double, Double> map,
+                                                   Double maxs, Double mins, Double maxp, Double minp, Boolean isfbw,
+                                                   Boolean isfhl, Boolean isbw, Boolean istj, Boolean isglpc, Boolean isqfh, Integer qfhdj){
+        String timeBW = DateUtil.format(new Date(0), DATE_TIME_PATTERN);
+        List<PowerPointData> tempei = new ArrayList<>();
+        List<PowerPointData> tempqf = new ArrayList<>();
+
+        //TODO 数据过滤  // 0正常,1过滤掉
+        for (PowerPointData item : list) {
+            int filter = 0;
+            int fjstatus = 0;
+            if (timeBW == DateUtil.format(new Date(0), DATE_TIME_PATTERN)){
+                timeBW = item.getTime();
+            }
+            // 过滤非并网值  风机状态不等于2
+            if (filter == 0 && isfbw && item.getMxzt() != 2) {
+                filter = 1;
+                fjstatus = 1;
+                timeBW = item.getTime();
+            } else {
+                filter = 0;
+                fjstatus = 0;
+            }
+            // 按给定风速功率过滤
+            if (item.getSpeed() < mins || item.getSpeed() > maxs || item.getPower() < minp || item.getPower() > maxp) {
+                filter = 1;
+            }
+            // 过滤非合理值 并网状态下功率小于等于0
+            if (filter == 0 && isfhl && item.getSpeed() < 0 && item.getPower() <= minp) {
+                filter = 1;
+            }
+            // 过滤并网后十分钟
+            if (filter == 0 && isbw) {
+                if (getTimeDiff(item.getTime(), timeBW) <= 10)
+                    filter = 1;
+            }
+            // 过滤停机前十分钟
+            if (istj) {
+                if (fjstatus == 0) {
+                    if (tempei.size() > 0) {
+                        if (getTimeDiff(tempei.get(0).getTime(), timeBW) >= 10) {
+                            tempei.remove(0);
+                        }
+                    }
+                    tempei.add(item);
+                } else {
+                    for (PowerPointData temp : tempei) {
+                        temp.setFilter(1);
+                    }
+                    tempei.clear();
+                }
+            }
+            //欠发
+            if (filter == 0 && item.getSpeed() >= 6 && item.getSpeed() < 12.5 && isqfh && qfhdj < item.getQfzt()) {
+                filter = 1;
+                for (PowerPointData temp : tempqf) {
+                    temp.setFilter(1);
+                }
+            } else if (filter == 0 && item.getSpeed() >= 12.5 && isqfh && qfhdj < 1) {
+                filter = 1;
+                for (PowerPointData temp : tempqf) {
+                    temp.setFilter(1);
+                }
+            }
+            if (tempqf.size() > 0) {
+                if (getTimeDiff(tempqf.get(0).getTime(), item.getTime()) >= 5) {
+                    tempqf.remove(0);
+                }
+            }
+            tempqf.add(0, item);
+            item.setFilter(filter);
+
+            //功率曲线偏差
+            if (isglpc) {
+                if (map.containsKey(item.getSpeed())) {
+                    double power = map.get(item.getSpeed());  //不同风速对应的保证功率
+                    double maxPower = map.get(24.0);     //最大保证功率
+                    double k = item.getPower() / power;  //保证功率/实际功率   k:偏差百分比
+                    if (item.getPower() > 0) {
+                        if (k < 0.95 && maxPower <= power) {
+                            item.setFilter(1);
+                        }
+                        if (k < 0.9 && maxPower > power) {
+                            item.setFilter(1);
+                        }
+                        if (k < 0.85 && item.getSpeed() < 6 && item.getSpeed() > 4) {
+                            item.setFilter(1);
+                        }
+
+                        if (k < 0.9 && item.getSpeed() <= 4 && item.getSpeed() > 3.5) {
+                            item.setFilter(1);
+                        }
+//                        if (k < 0.85 && item.getSpeed() <= 3.5 && item.getSpeed() > 3) {
+//                            item.setFilter(1);
+//                        }
+//                        if (k < 0.4 && item.getSpeed() <= 3 && item.getSpeed() > 0) {
+//                            item.setFilter(1);
+//                        }
+                    }
+                }
+            }
+        }
+
+        return list;
+    }
+
+
+    /**
+     * 按照给定风俗功率过滤
+     * @param list
+     * @param maxs  最大风速
+     * @param mins  最小风速
+     * @param maxp  最大功率
+     * @param minp  最小风速
+     * @return
+     */
+    public static List<PowerPointData> dataProcessPS(List<PowerPointData> list, Double maxs, Double mins, Double maxp, Double minp){
+        //TODO 数据过滤  // 0正常,1过滤掉
+        for (PowerPointData item : list) {
+            int filter = 0;
+            // 按给定风速功率过滤
+            if (item.getSpeed() < mins || item.getSpeed() > maxs || item.getPower() < minp || item.getPower() > maxp) {
+                filter = 1;
+            }
+
+            item.setFilter(filter);
+        }
+
+        return list;
+    }
+
+    /**
+     * 过滤非并网值
+     * @param list
+     * @return
+     */
+    public static List<PowerPointData> dataProcessFBW(List<PowerPointData> list){
+        //TODO 数据过滤  // 0正常,1过滤掉
+        for (PowerPointData item : list) {
+            int filter = 0;
+            // 过滤非并网值  风机状态不等于2
+            if (filter == 0 && item.getMxzt() != 2)
+                filter = 1;
+
+            item.setFilter(filter);
+        }
+
+        return list;
+    }
+
+
+    /**
+     * 过滤非合理值
+     * @param list
+     * @return
+     */
+    public static List<PowerPointData> dataProcessFHLZ(List<PowerPointData> list){
+        //TODO 数据过滤  // 0正常,1过滤掉
+        for (PowerPointData item : list) {
+            int filter = 0;
+            // 过滤非合理值 并网状态下功率小于等于0
+            if (filter == 0 && item.getMxzt() != 2 && item.getPower() <= 0) {
+                filter = 1;
+            }
+
+            item.setFilter(filter);
+        }
+
+        return list;
+    }
+
+    /**
+     * 过滤并网后几分钟内数据
+     * @param list
+     * @param minute  分钟
+     * @return
+     */
+    public static List<PowerPointData> dataProcessBWH(List<PowerPointData> list, int minute){
+        String timeBW = DateUtil.format(new Date(0), DATE_TIME_PATTERN);
+        //TODO 数据过滤  // 0正常,1过滤掉
+        for (PowerPointData item : list) {
+            int filter = 0;
+            if (timeBW == DateUtil.format(new Date(0), DATE_TIME_PATTERN)){
+                timeBW = item.getTime();
+            }
+            // 过滤并网后十分钟
+            if (filter == 0 && getTimeDiff(item.getTime(), timeBW) <= minute){
+                filter = 1;
+            }
+
+            item.setFilter(filter);
+        }
+
+        return list;
+    }
+
+
+    /**
+     * 过滤停机前几分钟内数据
+     * @param list
+     * @param minute  分钟
+     * @return
+     */
+    public static List<PowerPointData> dataProcessTJQ(List<PowerPointData> list, int minute){
+        String timeBW = DateUtil.format(new Date(0), DATE_TIME_PATTERN);
+        List<PowerPointData> tempei = new ArrayList<>();
+
+        //TODO 数据过滤  // 0正常,1过滤掉
+        for (PowerPointData item : list) {
+            int filter = 0;
+            int fjstatus = 0;
+            if (timeBW == DateUtil.format(new Date(0), DATE_TIME_PATTERN)){
+                timeBW = item.getTime();
+            }
+            if (filter == 0 && item.getMxzt() != 2) {
+                filter = 1;
+                fjstatus = 1;
+                timeBW = item.getTime();
+            } else {
+                filter = 0;
+                fjstatus = 0;
+            }
+            // 过滤停机前十分钟
+            if (fjstatus == 0) {
+                if (tempei.size() > 0) {
+                    if (getTimeDiff(tempei.get(0).getTime(), timeBW) >= minute) {
+                        tempei.remove(0);
+                    }
+                }
+                tempei.add(item);
+            } else {
+                for (PowerPointData temp : tempei) {
+                    temp.setFilter(1);
+                }
+                tempei.clear();
+            }
+
+            item.setFilter(filter);
+        }
+
+        return list;
+    }
+
+    /**
+     * 曲线偏差率过滤
+     * @param list
+     * @param map  风速对应的保证功率
+     * @return
+     */
+    public static List<PowerPointData> dataProcessQXPC(List<PowerPointData> list, Map<Double, Double> map){
+        //TODO 数据过滤  // 0正常,1过滤掉
+        for (PowerPointData item : list) {
+            if (map.containsKey(item.getSpeed())) {
+                double power = map.get(item.getSpeed());  //不同风速对应的保证功率
+                double maxPower = map.get(24.0);     //最大保证功率
+                double k = item.getPower() / power;  //保证功率/实际功率   k:偏差百分比
+                if (item.getPower() > 0) {
+                    if (k < 0.95 && maxPower <= power) {
+                        item.setFilter(1);
+                    }
+                    if (k < 0.9 && maxPower > power) {
+                        item.setFilter(1);
+                    }
+                    if (k < 0.85 && item.getSpeed() < 6 && item.getSpeed() > 4) {
+                        item.setFilter(1);
+                    }
+
+                    if (k < 0.9 && item.getSpeed() <= 4 && item.getSpeed() > 3.5) {
+                        item.setFilter(1);
+                    }
+                    if (k < 0.85 && item.getSpeed() <= 3.5 && item.getSpeed() > 3) {
+                        item.setFilter(1);
+                    }
+                    if (k < 0.4 && item.getSpeed() <= 3 && item.getSpeed() > 0) {
+                        item.setFilter(1);
+                    }
+                }
+            }
+        }
+
+        return list;
+    }
+
+    /**
+     * 根据欠发过滤
+     * @param list
+     * @param qfhdj 签发等级
+     * @return
+     */
+    public static List<PowerPointData> dataProcessQF(List<PowerPointData> list, int qfhdj){
+        List<PowerPointData> tempqf = new ArrayList<>();
+        //TODO 数据过滤  // 0正常,1过滤掉
+        for (PowerPointData item : list) {
+            int filter = 0;
+            //欠发
+            if (filter == 0 && item.getSpeed() >= 6 && item.getSpeed() < 12.5 && qfhdj < item.getQfzt()) {
+                filter = 1;
+                for (PowerPointData temp : tempqf) {
+                    temp.setFilter(1);
+                }
+            } else if (filter == 0 && item.getSpeed() >= 12.5 && qfhdj < 1) {
+                filter = 1;
+                for (PowerPointData temp : tempqf) {
+                    temp.setFilter(1);
+                }
+            }
+            if (tempqf.size() > 0) {
+                if (getTimeDiff(tempqf.get(0).getTime(), item.getTime()) >= 5) {
+                    tempqf.remove(0);
+                }
+            }
+            tempqf.add(0, item);
+            item.setFilter(filter);
+        }
+
+        return list;
+    }
+
+
+    public static int getTimeDiff(String oldTime, String newTime) {
+        int diff = 0;
+        SimpleDateFormat df = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
+        long NTime = 0;
+        long OTime = 0;
+        try {
+            NTime = df.parse(newTime).getTime();
+            //从对象中拿到时间
+            OTime = df.parse(oldTime).getTime();
+            diff = (int) (Math.abs((NTime-OTime))/1000/60);
+        } catch (ParseException e) {
+        }
+
+        return diff;
+    }
+}

+ 3 - 0
runeconomy-xk/src/main/java/com/gyee/runeconomy/model/auto/ProEconPowerFittingAnalySis.java

@@ -1,5 +1,7 @@
 package com.gyee.runeconomy.model.auto;
 
+import com.baomidou.mybatisplus.annotation.IdType;
+import com.baomidou.mybatisplus.annotation.TableId;
 import com.baomidou.mybatisplus.annotation.TableName;
 import com.baomidou.mybatisplus.extension.activerecord.Model;
 import lombok.Data;
@@ -22,6 +24,7 @@ public class ProEconPowerFittingAnalySis extends Model<ProEconPowerFittingAnalyS
 
     private static final long serialVersionUID=1L;
 
+    @TableId(value = "id", type = IdType.ASSIGN_UUID)
     private String id;
 
     private String station;

+ 3 - 1
runeconomy-xk/src/main/java/com/gyee/runeconomy/model/auto/TurbineInfoDay.java

@@ -8,6 +8,8 @@ import com.baomidou.mybatisplus.annotation.IdType;
 import java.time.LocalDate;
 import com.baomidou.mybatisplus.annotation.TableId;
 import java.io.Serializable;
+import java.util.Date;
+
 import lombok.Data;
 import lombok.EqualsAndHashCode;
 import lombok.experimental.Accessors;
@@ -44,7 +46,7 @@ public class TurbineInfoDay implements Serializable {
     private String turbineId;
 
     @TableField("record_date")
-    private LocalDate recordDate;
+    private Date recordDate;
 
     @TableField("rfdl")
     private BigDecimal rfdl;

+ 3 - 3
runeconomy-xk/src/main/java/com/gyee/runeconomy/model/vo/ComparetqVo.java

@@ -11,7 +11,7 @@ import lombok.Data;
 public class ComparetqVo {
 
     private String wtId;
-    private String recodedate;
-    private String recodedate2;
-    private String operation;
+    private double recodedate;
+    private double recodedate2;
+    private double operation;
 }

+ 3 - 3
runeconomy-xk/src/main/java/com/gyee/runeconomy/model/vo/GeneratingCapacityVo.java

@@ -12,7 +12,7 @@ import java.math.BigDecimal;
 @Data
 public class GeneratingCapacityVo {
     private String name;
-    private BigDecimal value;
-    private BigDecimal total;
-    private BigDecimal bfb;
+    private Double value;
+    private Double total;
+    private Double bfb;
 }

+ 8 - 3
runeconomy-xk/src/main/java/com/gyee/runeconomy/model/vo/PointVo.java

@@ -9,6 +9,11 @@ import lombok.NoArgsConstructor;
 @AllArgsConstructor
 public class PointVo {
 
-    private Double x;
-    private Double y;
-}
+    private double x;
+
+    private double y;
+
+    private double s;
+
+    private String k;
+}

+ 58 - 0
runeconomy-xk/src/main/java/com/gyee/runeconomy/service/DBSCANPointALG.java

@@ -0,0 +1,58 @@
+package com.gyee.runeconomy.service;
+
+
+import com.gyee.runeconomy.dto.result.PowerPointData;
+
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+
+/**
+ * 散点聚合
+ */
+public class DBSCANPointALG {
+
+    /**
+     * 功率曲线拟合 散点聚合
+     * @param points  散点list
+     * @param param   聚合参数  10
+     * @return
+     */
+    public static  Map<String, List<PowerPointData>> dbscan(List<PowerPointData> points, double param){
+        Map<String, List<PowerPointData>> map = new HashMap<>();
+
+        for (PowerPointData item : points){
+            double x = item.getSpeed() * param;
+            double y = item.getPower() / param;
+
+            String key = Math.round(x) +  String.valueOf(Math.round(y));
+
+            if (!map.containsKey(key)){
+                map.put(key, new ArrayList<>());
+            }
+            map.get(key).add(item);
+        }
+
+        return map;
+    }
+
+//    public static  Map<String, List<PhotovoltaicInfo>> dbgfscan(List<PhotovoltaicInfo> points, double param){
+//        Map<String, List<PhotovoltaicInfo>> map = new HashMap<>();
+//
+//        for (PhotovoltaicInfo item : points){
+//            double x = item.getS() * param;
+//            double y = item.getActualP() / param;
+//
+//            String key = Math.round(x) +  String.valueOf(Math.round(y));
+//
+//            if (!map.containsKey(key)){
+//                map.put(key, new ArrayList<>());
+//            }
+//            map.get(key).add(item);
+//        }
+//
+//        return map;
+//    }
+
+}

+ 25 - 0
runeconomy-xk/src/main/java/com/gyee/runeconomy/service/DataScanService.java

@@ -0,0 +1,25 @@
+package com.gyee.runeconomy.service;
+
+import com.gyee.runeconomy.dto.result.PowerPointData;
+import lombok.Data;
+import org.springframework.stereotype.Component;
+
+import java.util.List;
+import java.util.Map;
+
+/**
+ * 散点聚合实例
+ */
+@Data
+@Component
+public class DataScanService {
+
+    public Map<String, List<PowerPointData>> mapYY;
+
+    public Map<String, List<PowerPointData>> mapWY;
+
+    public Map<String,List<PowerPointData>> onlyMap;
+
+
+
+}

+ 600 - 0
runeconomy-xk/src/main/java/com/gyee/runeconomy/service/auto/impl/NewDataFittingService.java

@@ -0,0 +1,600 @@
+package com.gyee.runeconomy.service.auto.impl;
+
+import com.baomidou.mybatisplus.core.toolkit.StringUtils;
+import com.gyee.runeconomy.config.GyeeConfig;
+import com.gyee.runeconomy.dto.FiveLoss.AnnotationTool;
+import com.gyee.runeconomy.dto.FiveLoss.FixedVo;
+import com.gyee.runeconomy.dto.FiveLoss.TableTitle;
+import com.gyee.runeconomy.dto.result.PowerPointData;
+import com.gyee.runeconomy.dto.speed.WindDirectionALG;
+import com.gyee.runeconomy.init.CacheContext;
+import com.gyee.runeconomy.model.LineCurveFitting;
+import com.gyee.runeconomy.model.PowerFittingALG;
+import com.gyee.runeconomy.model.PowerFittingData;
+import com.gyee.runeconomy.model.PowerProcessALG;
+import com.gyee.runeconomy.model.auto.*;
+import com.gyee.runeconomy.model.vo.NewDataFittingVo;
+import com.gyee.runeconomy.model.vo.PointVo;
+import com.gyee.runeconomy.service.DBSCANPointALG;
+import com.gyee.runeconomy.service.DataScanService;
+import com.gyee.runeconomy.service.WindDirection.Point;
+import com.gyee.runeconomy.util.FileUtil;
+import com.gyee.runeconomy.util.SnowFlakeUtil;
+import com.gyee.runeconomy.util.realtimesource.feign.RemoteServiceBuilder;
+import com.gyee.runeconomy.util.realtimesource.feign.TsDoubleData;
+import lombok.extern.slf4j.Slf4j;
+import lombok.val;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.stereotype.Service;
+
+import javax.annotation.Resource;
+import java.text.DecimalFormat;
+import java.text.SimpleDateFormat;
+import java.util.*;
+import java.util.concurrent.TimeUnit;
+import java.util.concurrent.atomic.AtomicReference;
+import java.util.stream.Collectors;
+
+@Slf4j
+@Service
+public class NewDataFittingService {
+    @Autowired
+    private GyeeConfig config;
+
+
+    @Autowired
+    private RemoteServiceBuilder remoteService;
+
+    @Autowired
+    private ProEconPowerFittingAnalySisService proEconPowerFittingAnalySisService;
+
+    public static final String DATA_PROCESS = "process";
+
+    public static final String DATA_FITTING = "fitting";
+
+//    private List<List<TsDoubleData>> res = new ArrayList<>();
+
+//    private List<PowerPointData> dataFilter = new ArrayList<>();
+
+
+    @Resource
+    private DataScanService dataScanService;
+
+
+    //数据map
+    private Map<String, String> prepareMap = null;//数据准备map
+    private Map<String, String> processMap = null;//数据处理map
+    private Map<String, String> fittingMap = null;//数据拟合map
+
+    /**
+     * 数据准备拟合
+     *
+     * @param vo
+     * @return
+     */
+    public ProEconPowerFittingAnalySis newDataFitting(NewDataFittingVo vo) {
+        prepareMap = new HashMap<>();
+        processMap = new HashMap<>();
+        fittingMap = new HashMap<>();
+
+        //1.数据获取
+        List<String> wtIds = Arrays.asList(vo.getWtIds().split(","));
+//        deleteDir(config.getFilePathPrepare());
+        for (int k = 0; k < wtIds.size(); k++) {
+            String wt = wtIds.get(k);
+            List<List<TsDoubleData>> result = new ArrayList<>();
+
+            try {
+                List<String> points = config.getPoints();
+//                Map<String, List<ProBasicEquipmentPoint>> collect = CacheContext.pointNewMap.get(wt).stream().collect(Collectors.groupingBy(w -> w.getUniformCode()));
+                Map<String, List<ProBasicEquipmentPoint>> collect = CacheContext.pointNewMap.get(wt).stream().collect(Collectors.groupingBy(w -> w.getUniformCode()));
+                if (collect.size() < 8)
+                    continue;
+                for (int i = 0; i < points.size(); i++) {
+                    ProBasicEquipmentPoint point = collect.get(points.get(i)).get(0);
+                    log.info("测点:" + point.getId() + "----" + point.getName());
+                    List<TsDoubleData> data = remoteService.adapterfd().getHistorySnap(point.getNemCode(), vo.getSt(), vo.getEt(), vo.getInterval());
+//                    List<TsDoubleData> data = edosUtil.getHistorySnap(point.getNemCode(), vo.getSt(), vo.getEt(), vo.getInterval());
+//                    List<PointData> data = edosUtil.getHistoryDatasSnap(point.getNemCode(), vo.getSt(), vo.getEt(), vo.getInterval());
+                    if (data == null || data.size() == 0)
+                        break;
+                    result.add(data);
+                    TimeUnit.MILLISECONDS.sleep(200);
+                }
+                if (result.size() != points.size())
+                    continue;
+
+                String content = prepareAssemble(result);
+//                 处理的数据保存在本地
+                String wtCode = CacheContext.wtmap.get(wt).getId();
+                String wtCode2 = CacheContext.wtmap.get(wt).getNemCode();
+                String fileName = config.getFilePathPrepare() + vo.getStation() + "_" + wtCode + "_" + System.currentTimeMillis() / 1000 + ".csv";
+                boolean flag = FileUtil.writeFile(fileName, content);
+
+                if (flag){  // TODO  保存数据库
+                ProEconPowerFittingAnalySis obj = new ProEconPowerFittingAnalySis();
+                obj.setStation(vo.getStation());
+                obj.setStationcn(CacheContext.wtstandardmap.get(vo.getStation()));
+                obj.setWindturbineId(wt);
+                obj.setCode(wtCode2);
+//                    obj.setTime(DateUtil.format(vo.getSt(), "yyyy年MM月dd日") + "-" + DateUtil.format(vo.getEt(), "yyyy年MM月dd日"));
+                SimpleDateFormat sdf = new SimpleDateFormat("yyyy年MM月dd日");
+                obj.setTime(sdf.format(new Date(vo.getSt())) + "-" + sdf.format(new Date(vo.getEt())));
+                obj.setInterval(vo.getInterval().toString());
+                obj.setPath(fileName);
+                obj.setType("prepare");
+                obj.setInterp(vo.getInterval());
+                proEconPowerFittingAnalySisService.saveOrUpdate(obj);
+                prepareMap.put(obj.getId(),fileName);//保存拿到的数据
+                }
+                System.out.println("数据准备完成:" + wt);
+            } catch (Exception e) {
+                e.printStackTrace();
+            }
+        }
+
+
+        //2.数据筛选
+        try {
+            for (String key : prepareMap.keySet()) {
+                ProEconPowerFittingAnalySis obj = proEconPowerFittingAnalySisService.getById(key);
+                /** 读取csv数据  转换成对象数组 **/
+                List<PowerPointData> eis = new ArrayList<>();
+                List<String> list = FileUtil.readFile(prepareMap.get(key), true);
+//                String s = prepareAssemble(res);
+//                String[] lines = s.split("\n");
+//                List<String> list = new ArrayList<>(Arrays.asList(lines));
+                for (int i = 1; i < list.size(); i++) {
+                    eis.add(new PowerPointData(list.get(i).split(","), false));
+                }
+
+                /** 风速  ->  保证功率  来自数据库 **/
+                List<ProBasicModelPower> modelPowerList = CacheContext.modelPowerDetailNewMap.get(CacheContext.wtmap.get(obj.getWindturbineId()).getModelId());
+                Map<Double, Double> modelPowerMap = modelPowerList.stream().collect(Collectors.toMap(ProBasicModelPower::getSpeed, ProBasicModelPower::getEnsurePower));
+                /** 数据预处理 **/
+                List<PowerPointData> data = PowerProcessALG.dataProcess(eis, modelPowerMap, vo.getMaxs(), vo.getMins(), vo.getMaxp(), vo.getMinp(), vo.getIsfbw(), vo.getIsfhl(), vo.getIsbw(), vo.getIstj(), vo.getIsglpc(), vo.getIsqfh(), vo.getQfhdj());
+                /** 静风频率 **/
+                List<Double> ls = WindDirectionALG.frequency(data.stream().map(PowerPointData::getSpeed).collect(Collectors.toList()), 3);
+                double frequency = ls.get(0);
+                double speed = ls.get(1);
+
+                String content = processAssemble(data);
+                String fileName = config.getFilePathProcess() + vo.getStation() + "_" + obj.getWindturbineId() + "_" + SnowFlakeUtil.generateIdL() / 100000 + ".csv";
+                boolean flag = FileUtil.writeFile(fileName, content);
+
+                if (flag) {  // TODO  保存数据库
+//                    obj.setId(null);
+                    obj.setPath(fileName);
+                obj.setFrequency(frequency);
+                obj.setSpeedavg(speed);
+                obj.setType(DATA_PROCESS);
+                proEconPowerFittingAnalySisService.saveOrUpdate(obj);
+                    processMap.put(obj.getId(),fileName);//保存预处理的的数据
+                }
+
+                System.out.println("功率曲线拟合数据预处理完成:" + obj.getWindturbineId());
+            }
+        } catch (Exception e) {
+            e.printStackTrace();
+        }
+        //3.数据拟合
+
+        AtomicReference<ProEconPowerFittingAnalySis> object = new AtomicReference<>();
+//        deleteDir(config.getFilePathFitting());
+        if (vo.getMode() == 0) {  //单台拟合
+            for (String processkey : processMap.keySet()) {
+                List<ProEconPowerFittingAnalySis> list = proEconPowerFittingAnalySisService.selectListByIds(processkey);
+                List<Double> arraySpeed = new ArrayList<>();
+                List<Double> arrayPower = new ArrayList<>();
+                List<String> line = FileUtil.readFile(processMap.get(processkey), true);
+//                String content = processAssemble(dataFilter);
+//                String[] lines = content.split("\n");
+//                List<String> line = new ArrayList<>(Arrays.asList(lines));
+                csvParse(line, arraySpeed, arrayPower, vo.getMins(), vo.getMaxs(), vo.getMinp(), vo.getMaxp());
+                List<ProBasicModelPower> mp = CacheContext.modelPowerDetailNewMap.get(CacheContext.wtmap.get(list.get(0).getWindturbineId()).getModelId());
+                Double maxP = mp.stream().map(ProBasicModelPower::getEnsurePower).max(Comparator.comparing(Double::doubleValue)).get();
+                object.set(fittingMode(list, maxP, arraySpeed, arrayPower, vo.getDimension(), vo.getMode()));
+
+            }
+        }
+        if (vo.getMode() == 1) {  //合并拟合
+
+            AtomicReference<Double> maxP = new AtomicReference<>(0.0);
+            List<Double> arraySpeed = new ArrayList<>();
+            List<Double> arrayPower = new ArrayList<>();
+            StringBuffer ids = new StringBuffer();
+            for (String processkey : processMap.keySet()) {
+                ids.append(processkey).append(",");
+                ProEconPowerFittingAnalySis fittingAnalySis = proEconPowerFittingAnalySisService.getById(processkey);
+                List<String> line = FileUtil.readFile(processMap.get(processkey), true);
+//                String content = processAssemble(dataFilter);
+//                String[] lines = content.split("\n");
+//                List<String> line = new ArrayList<>(Arrays.asList(lines));
+                csvParse(line, arraySpeed, arrayPower, vo.getMins(), vo.getMaxs(), vo.getMinp(), vo.getMaxp());
+                List<ProBasicModelPower> mp = CacheContext.modelPowerDetailNewMap.get(CacheContext.wtmap.get(fittingAnalySis.getWindturbineId()).getModelId());
+                Double maxPower = mp.stream().map(ProBasicModelPower::getEnsurePower).max(Comparator.comparing(Double::doubleValue)).get();
+                if (maxPower > maxP.get()) maxP.set(maxPower);
+            }
+            List<ProEconPowerFittingAnalySis> list = proEconPowerFittingAnalySisService.selectListByIds(ids.toString());
+
+            object.set(fittingMode(list, maxP.get(), arraySpeed, arrayPower, vo.getDimension(), vo.getMode()));
+        }
+        if (vo.getMode() == 2) {
+            //同名拟合(暂时不支持)
+        }
+        fittingMap.put(object.get().getId(),object.get().getPath());
+
+        return object.get();
+    }
+
+
+
+    /**
+     * 曲线,散点等数据
+     * 风速 eg:[1,2,3,4。。。。]
+     * 曲线 eg:[1,2,3,4。。。。]
+     * 散点 eg:[[1,2],[3,2],[3,5]。。。。。]
+     * @param id
+     * @return
+     */
+    public Map<String, Object> dataFittingCurve(String id){
+
+        Map<String, Object> map = new HashMap<>();
+        ProEconPowerFittingAnalySis obj = proEconPowerFittingAnalySisService.selectItemById(id);
+
+        //实际功率、风速、Cp值
+        List<Object> sjglList = new ArrayList<>();
+        List<Object> cpzList = new ArrayList<>();
+        List<String> ls = FileUtil.readFile(obj.getPath(), true);
+        for (int i = 1; i < ls.size(); i++){
+            PowerFittingData data = new PowerFittingData(ls.get(i).split(","));
+            sjglList.add(new double[]{Double.valueOf(data.getSpeed()), data.getNhdata()});
+            cpzList.add(new double[]{Double.valueOf(data.getSpeed()), data.getCpdata()});
+        }
+
+        //保证功率
+        List<ProBasicModelPower> modelPower = CacheContext.modelPowerDetailNewMap.get(CacheContext.wtmap.get(obj.getWindturbineId()).getModelId());
+        List<Object> bzglList = modelPower.stream().sorted(Comparator.comparing(ProBasicModelPower::getSpeed)).map(m -> new double[]{m.getSpeed(), m.getEnsurePower()}).collect(Collectors.toList());
+
+        //散点
+        String[] ids = obj.getProcessid().split(",");
+        List<PowerPointData> yyd = new ArrayList<>(); //有用点
+        List<PowerPointData> wyd = new ArrayList<>(); //无用点
+        for (String pid : ids){
+            ProEconPowerFittingAnalySis pf = proEconPowerFittingAnalySisService.selectItemById(pid);
+            List<String> lp = FileUtil.readFile(pf.getPath(), true);
+            for (int i = 1; i < lp.size(); i++){
+                String[] split = lp.get(i).split(",");
+                PowerPointData pd = new PowerPointData(split, true);
+                if (pd.getSpeed() < 0 || pd.getPower() < 0)
+                    continue;
+                pd.setWtId(pf.getWindturbineId());
+                if (0 == pd.getFilter())
+                    yyd.add(pd);   //没有过滤
+                if (1 == pd.getFilter())
+                    wyd.add(pd);   //已过滤
+            }
+        }
+
+        dataScanService.setMapYY(DBSCANPointALG.dbscan(yyd, 10));
+        dataScanService.setMapWY(DBSCANPointALG.dbscan(wyd, 10));
+
+        List<PointVo> listYY = new ArrayList<>();
+        List<PointVo> listWY = new ArrayList<>();
+        dataScanService.getMapYY().forEach((k, v) -> {
+            // k: 前端画圈时的散点数据标记
+            listYY.add(new PointVo(v.get(0).getSpeed(), v.get(0).getPower(), dataScanService.getMapYY().get(k).size() + 3, k));
+        });
+        dataScanService.getMapWY().forEach((k, v) -> {
+            // k: 前端画圈时的散点数据标记
+            listWY.add(new PointVo(v.get(0).getSpeed(), v.get(0).getPower(), dataScanService.getMapWY().get(k).size() + 3, k));
+        });
+
+        map.put("sjgl", sjglList);    //实际功率
+        map.put("llgl", bzglList);    //保证功率
+        map.put("cpz", cpzList);      //Cp值
+        map.put("obj", obj);     //对w象
+        map.put("yyd", listYY);  //有用散点
+        map.put("wyd", listWY);  //无用散点
+
+        return map;
+    }
+
+
+
+
+
+    /**
+     * 通过大点的key获取小散点
+     * @param yk
+     * @param wk
+     * @return
+     */
+    public List<PowerPointData> dataOrigin(String yk, String wk) {
+        List<PowerPointData> list = new ArrayList<>();
+
+        if (!StringUtils.isEmpty(yk)){
+            String[] key = yk.split(",");
+            for (String k : key){
+                list.addAll(dataScanService.getMapYY().get(k));
+            }
+        }
+        if (!StringUtils.isEmpty(wk)){
+            String[] kew = wk.split(",");
+            for (String k : kew){
+                list.addAll(dataScanService.getMapWY().get(k));
+            }
+        }
+
+        return list;
+    }
+
+
+    /**
+     * 组装表格数据
+     *
+     * @param id
+     * @return
+     */
+    public Map<String, Object> dataFittingShow(String id) {
+        Map<String, Object> map = new HashMap<>();
+
+        /** 添加标题 **/
+        List<FixedVo> fxList = AnnotationTool.getFixedVoList(PowerFittingData.class);
+        List<TableTitle> lt = fxList.stream().filter(f -> f.getRemark().equals("1"))
+                .map(d -> new TableTitle(d.getName(), d.getDes())).collect(Collectors.toList());
+
+        /** 添加内容 **/
+        /** 添加内容 **/
+        List<PowerFittingData> list = new ArrayList<>();
+        ProEconPowerFittingAnalySis obj = proEconPowerFittingAnalySisService.selectItemById(id);
+        List<String> ls = FileUtil.readFile(obj.getPath(), false);
+        for (int i = 1; i < ls.size(); i++){
+            PowerFittingData data = new PowerFittingData(ls.get(i).split(","));
+            list.add(data);
+        }
+
+        map.put("title", lt);
+        map.put("data", list);
+
+        return map;
+    }
+
+
+        private String prepareAssemble(List<List<TsDoubleData>> list){
+            if (list.size() == 0)
+                return null;
+
+            StringBuilder sb = setTitle();
+            List<TsDoubleData> data = list.get(0);
+            for (int i = 0; i < data.size(); i++){
+//                sb.append(DateUtil.format(data.get(i).getTs(), DateUtil.DATE_TIME_PATTERN)).append(",");
+                SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
+                sb.append(sdf.format(data.get(i).getTs())).append(",");
+                sb.append(data.get(i).getDoubleValue()).append(",");
+                for (int j = 1; j < list.size(); j++){
+
+                    //
+                    if(null != list.get(j) && list.get(j).size()>0){
+                        sb.append(list.get(j).get(i).getDoubleValue()).append(",");
+                    }else {
+                        sb.append(0).append(",");
+                    }
+
+                }
+                sb.deleteCharAt(sb.lastIndexOf(","));
+                sb.append("\n");
+            }
+
+            return sb.toString();
+        }
+
+
+    private String processAssemble(List<PowerPointData> list) {
+        StringBuilder sb = setTitle();
+        for (PowerPointData obj : list) {
+            List<FixedVo> ls = AnnotationTool.getValueList(obj);
+            String data = ls.stream().filter(f -> !StringUtils.isEmpty(f.getRemark())).map(FixedVo::getKey).collect(Collectors.joining(","));
+            sb.append(data).append("\n");
+        }
+
+        return sb.toString();
+    }
+
+
+    private StringBuilder setTitle() {
+        StringBuilder sb = new StringBuilder();
+        val list = AnnotationTool.getFixedVoList(PowerPointData.class);
+        String columnName = list.stream().filter(f -> f.getRemark().equals("1")).map(FixedVo::getDes).collect(Collectors.joining(","));
+        sb.append(columnName).append("\n");
+        return sb;
+    }
+
+
+    /**
+     * 读取csv数据 转换成对象数组
+     **/
+    private void csvParse(List<String> line, List<Double> arrayS, List<Double> arrayP, double mins, double maxs, double minp, double maxp) {
+        for (int i = 1; i < line.size(); i++) {
+            String[] split = line.get(i).split(",");
+            PowerPointData data = new PowerPointData(split, true);//是否过滤 0:没过滤 1:过滤
+            double x = data.getSpeed();    //风速
+            double y = data.getPower();    //功率
+            int filter = data.getFilter();
+            if (filter == 0 && (x >= mins && x <= maxs && y >= minp && y <= maxp)) {
+                arrayS.add(x);
+                arrayP.add(y);
+            }
+        }
+    }
+
+
+    private ProEconPowerFittingAnalySis fittingMode(List<ProEconPowerFittingAnalySis> list, Double powerMax, List<Double> arraySpeed, List<Double> arrayPower, Integer dimension, int mode) {
+        if (list == null || list.size() == 0)
+            return null;
+
+        ProEconPowerFittingAnalySis obj = list.get(0);
+        //风速0-25,数据不全拟合的则不全,需要补一下
+        arraySpeed.add(0.0);
+        arraySpeed.add(25.01);
+        arrayPower.add(0.0);
+        arrayPower.add(powerMax);
+        double[] arrX = arraySpeed.stream().sorted().mapToDouble(i -> i).toArray();
+        double[] arrY = arrayPower.stream().sorted().mapToDouble(i -> i).toArray();
+
+        //功率曲线拟合 不合理数据过滤
+        List<Point> temp = PowerFittingALG.buildLine(arrX, arrY, arraySpeed.size(), dimension, 0.01);
+        //推力系数 CP值
+        LineCurveFitting lf = new LineCurveFitting();
+        lf.setYLines(temp);
+
+        lf = PowerFittingALG.buildCp(CacheContext.modelMap.get(CacheContext.wtmap.get(obj.getWindturbineId()).getModelId()).getSweptArea(), lf);
+        lf.getCpValue().forEach(f -> {
+            if (f.getX() <= 2.5) f.setY(0);
+        });
+        //曲线偏差率
+        dataCurveRatio(lf, obj);
+
+        String content = fittingAssemble(lf);
+        String processId = "";
+        String fileName = null;
+        if (mode == 0){
+            processId = obj.getId();
+            fileName = config.getFilePathFitting() + obj.getStation() + "_" + obj.getCode() + "_" + SnowFlakeUtil.generateIdL() / 100000 + ".csv";
+        }
+        if (mode == 1){
+            processId = list.stream().map(d -> d.getId()).collect(Collectors.joining(","));
+            fileName = config.getFilePathFitting() + obj.getStation() + "_merge" + "_" + SnowFlakeUtil.generateIdL() / 100000 + ".csv";
+        }
+        if (mode == 2){
+            processId = list.stream().map(d -> d.getId()).collect(Collectors.joining(","));
+            fileName = config.getFilePathFitting() + obj.getStation() + "_same" + "_" + SnowFlakeUtil.generateIdL() / 100000 + ".csv";
+        }
+        boolean flag = FileUtil.writeFile(fileName, content);
+        if (flag) {  // TODO  保存数据库
+//        obj.setId(null);
+        obj.setPath(fileName);
+        obj.setProcessid(processId);
+        obj.setCpavg(lf.getCpAvg());
+        obj.setType(DATA_FITTING);
+        proEconPowerFittingAnalySisService.saveOrUpdate(obj);
+        }
+        System.out.println("功率曲线拟合完成:" + obj.getWindturbineId());
+
+        return obj;
+    }
+
+
+    /**
+     * 曲线偏差率  分段的+全部的
+     * 3-5  5-10  10-12  12-25
+     *
+     * @return
+     */
+    private void dataCurveRatio(LineCurveFitting lf, ProEconPowerFittingAnalySis obj) {
+        DecimalFormat df = new DecimalFormat("0.00");
+        try {
+            //风速、实际功率
+            List<Point> point = new ArrayList<>();  //3-25m
+            List<Point> point5 = new ArrayList<>();  //分段
+            List<Point> point10 = new ArrayList<>();  //分段
+            List<Point> point12 = new ArrayList<>();  //分段
+            List<Point> point25 = new ArrayList<>();  //分段
+            List<Point> line = lf.getYLines();
+            for (int i = 1; i < line.size(); i++) {
+                double speed = Double.valueOf(df.format(line.get(i).getX()));
+                if (speed >= 3 && speed < 5)
+                    point5.add(new Point(speed, line.get(i).getY()));
+                if (speed >= 5 && speed < 10)
+                    point10.add(new Point(speed, line.get(i).getY()));
+                if (speed >= 10 && speed < 12)
+                    point12.add(new Point(speed, line.get(i).getY()));
+                if (speed >= 12 && speed <= 25)
+                    point25.add(new Point(speed, line.get(i).getY()));
+                if (speed >= 3 && speed <= 25) {
+                    point.add(new Point(speed, line.get(i).getY()));
+                }
+            }
+
+            //保证功率
+            List<Point> points = new ArrayList<>();  //3-25m
+            List<Point> points5 = new ArrayList<>();  //分段
+            List<Point> points10 = new ArrayList<>();  //分段
+            List<Point> points12 = new ArrayList<>();  //分段
+            List<Point> points25 = new ArrayList<>();  //分段
+            List<ProBasicModelPower> list = CacheContext.modelPowerDetailNewMap.get(CacheContext.wtmap.get(obj.getWindturbineId()).getModelId());
+            for (int i = 0; i < list.size(); i++) {
+                ProBasicModelPower power = list.get(i);
+                if (power.getSpeed() >= 3 && power.getSpeed() < 5)
+                    points5.add(new Point(power.getSpeed(), power.getEnsurePower()));
+                if (power.getSpeed() >= 5 && power.getSpeed() < 10)
+                    points10.add(new Point(power.getSpeed(), power.getEnsurePower()));
+                if (power.getSpeed() >= 10 && power.getSpeed() < 12)
+                    points12.add(new Point(power.getSpeed(), power.getEnsurePower()));
+                if (power.getSpeed() >= 12 && power.getSpeed() <= 25)
+                    points25.add(new Point(power.getSpeed(), power.getEnsurePower()));
+                if (power.getSpeed() >= 3 && power.getSpeed() <= 25)
+                    points.add(new Point(power.getSpeed(), power.getEnsurePower()));
+            }
+
+            double maxp5 = list.stream().filter(f -> 5.0 == f.getSpeed()).collect(Collectors.toList()).get(0).getEnsurePower();
+            double maxp10 = list.stream().filter(f -> 10.0 == f.getSpeed()).collect(Collectors.toList()).get(0).getEnsurePower();
+            double maxp12 = list.stream().filter(f -> 12.0 == f.getSpeed()).collect(Collectors.toList()).get(0).getEnsurePower();
+            double maxp25 = list.stream().filter(f -> 25.0 == f.getSpeed()).collect(Collectors.toList()).get(0).getEnsurePower();
+
+            //曲线偏差率
+            double pcl = PowerFittingALG.curveDeviationRatio2(point, points, maxp25, 3, 25);
+            double pcl5 = PowerFittingALG.curveDeviationRatio2(point5, points5, maxp5, 3, 5);
+            double pcl10 = PowerFittingALG.curveDeviationRatio2(point10, points10, maxp10, 5, 10);
+            double pcl12 = PowerFittingALG.curveDeviationRatio2(point12, points12, maxp12, 10, 12);
+            double pcl25 = PowerFittingALG.curveDeviationRatio2(point25, points25, maxp25, 12, 25);
+
+            obj.setPcratio(Double.valueOf(df.format(pcl)));
+            obj.setPc5ratio(Double.valueOf(df.format(pcl5)));
+            obj.setPc10ratio(Double.valueOf(df.format(pcl10)));
+            obj.setPc12ratio(Double.valueOf(df.format(pcl12)));
+            obj.setPc25ratio(Double.valueOf(df.format(pcl25)));
+
+        } catch (Exception e) {
+            log.error("DataFittingService--dataCurveRatio", e);
+        }
+    }
+
+    private String fittingAssemble(LineCurveFitting lf) {
+        StringBuilder sb = setTitle();
+        for (int i = 0; i < lf.getYLines().size(); i++) {
+            Point cp = lf.getCpValue().get(i);
+            Point gl = lf.getYLines().get(i);
+
+            String stx = String.format("%.2f", gl.getX());
+            double x = Double.parseDouble(stx);
+            String sty = String.format("%.2f", gl.getY());
+            double y = Double.parseDouble(sty);
+            String stcp = String.format("%.4f", cp.getY());
+            double z = Double.parseDouble(stcp);
+            sb.append(x).append(",").append(y).append(",").append(z).append("\n");
+        }
+
+        return sb.toString();
+    }
+
+
+//
+//    private boolean deleteDir(String path){
+//         boolean  b  =false;
+//        File directory = new File(path);
+//        for (File file: Objects.requireNonNull(directory.listFiles())) {
+//            if (!file.isDirectory()) {
+//                b = file.delete();
+//                if(!b){
+//                    return b;
+//                }
+//            }
+//        }
+//        return b;
+//
+//    }
+
+
+}
+

+ 41 - 0
runeconomy-xk/src/main/java/com/gyee/runeconomy/service/auto/impl/ProEconPowerFittingAnalySisService.java

@@ -0,0 +1,41 @@
+package com.gyee.runeconomy.service.auto.impl;
+
+import com.baomidou.mybatisplus.extension.service.IService;
+import com.gyee.runeconomy.model.auto.ProEconPowerFittingAnalySis;
+
+import java.util.List;
+
+/**
+ * <p>
+ *  服务类
+ * </p>
+ *
+ * @author chenmh
+ * @since 2023-09-24
+ */
+public interface ProEconPowerFittingAnalySisService extends IService<ProEconPowerFittingAnalySis> {
+
+    ProEconPowerFittingAnalySis selectItemById(String id);
+
+    /**
+     * 根据类型查询
+     * @param type   prepare
+     * @return
+     */
+    List<ProEconPowerFittingAnalySis> selectList(List<String> stations ,String type);
+
+//    void insertItem(ProEconPowerFittingAnalySis obj);
+
+    List<ProEconPowerFittingAnalySis> selectListByIds(String ids);
+
+    void deleteList(String ids);
+
+    /**
+     * 查询准备的数据
+     * @param type  Constants.DATA_PREPARE  Constants.DATA_PROCESS
+     * @param isCal
+     * @return
+     */
+    List<ProEconPowerFittingAnalySis> selectListByIsCal(String type, int isCal);
+
+}

+ 105 - 0
runeconomy-xk/src/main/java/com/gyee/runeconomy/service/auto/impl/ProEconPowerFittingAnalySisServiceImpl.java

@@ -0,0 +1,105 @@
+package com.gyee.runeconomy.service.auto.impl;
+
+import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
+import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
+import com.gyee.runeconomy.mapper.auto.ProEconPowerFittingAnalySisMapper;
+import com.gyee.runeconomy.model.auto.ProEconPowerFittingAnalySis;
+import org.springframework.stereotype.Service;
+
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.Collections;
+import java.util.List;
+
+/**
+ * <p>
+ *  服务实现类
+ * </p>
+ *
+ * @author chenmh
+ * @since 2023-09-24
+ */
+@Service
+public class ProEconPowerFittingAnalySisServiceImpl extends ServiceImpl<ProEconPowerFittingAnalySisMapper, ProEconPowerFittingAnalySis> implements ProEconPowerFittingAnalySisService {
+
+    @Override
+    public ProEconPowerFittingAnalySis selectItemById(String id) {
+        ProEconPowerFittingAnalySis obj = new ProEconPowerFittingAnalySis();
+
+        QueryWrapper<ProEconPowerFittingAnalySis> wrapper = new QueryWrapper<>();
+        wrapper.eq("id", id);
+        try{
+            obj = baseMapper.selectOne(wrapper);
+        }catch (Exception e){
+            log.error("PowerfittinganalysisServiceImpl--selectItemById", e);
+        }
+
+        return obj;
+    }
+
+    @Override
+    public List<ProEconPowerFittingAnalySis> selectList(List<String> stations,String type) {
+        List<ProEconPowerFittingAnalySis> list = new ArrayList();
+
+        QueryWrapper<ProEconPowerFittingAnalySis> wrapper = new QueryWrapper<>();
+        wrapper.eq("type", type);
+
+
+        wrapper.in("station", stations);
+
+        try{
+            list = baseMapper.selectList(wrapper);
+        }catch (Exception e){
+            log.error("PowerfittinganalysisServiceImpl--selectList", e);
+        }
+
+        return list;
+    }
+
+//    @Override
+//    public void insertItem(ProEconPowerFittingAnalySis obj) {
+//        if (obj == null)
+//            return;
+//
+//        obj.setId(SnowFlakeUtil.generateId());
+//        try{
+//            baseMapper.insert(obj);
+//        }catch (Exception e){
+//            log.error("PowerfittinganalysisServiceImpl--insertItem", e);
+//        }
+//    }
+
+    @Override
+    public List<ProEconPowerFittingAnalySis> selectListByIds(String ids) {
+        try{
+            return baseMapper.selectBatchIds(Arrays.asList(ids.split(",")));
+        }catch (Exception e){
+            log.error("PowerfittinganalysisServiceImpl--selectListByIds", e);
+        }
+
+        return Collections.EMPTY_LIST;
+    }
+
+    @Override
+    public void deleteList(String ids) {
+        try{
+            baseMapper.deleteBatchIds(Arrays.asList(ids.split(",")));
+        }catch (Exception e){
+            log.error("PowerfittinganalysisServiceImpl--deleteList", e);
+        }
+    }
+
+    @Override
+    public List<ProEconPowerFittingAnalySis> selectListByIsCal(String type, int isCal) {
+        QueryWrapper<ProEconPowerFittingAnalySis> wrapper = new QueryWrapper<>();
+        wrapper.eq("type", type);
+        wrapper.eq("iscal", isCal);
+        try{
+            return baseMapper.selectList(wrapper);
+        }catch (Exception e){
+            log.error("PowerfittinganalysisServiceImpl--selectListByIsCal", e);
+        }
+
+        return Collections.EMPTY_LIST;
+    }
+}

+ 288 - 0
runeconomy-xk/src/main/java/com/gyee/runeconomy/util/FileUtil.java

@@ -0,0 +1,288 @@
+package com.gyee.runeconomy.util;
+
+import lombok.extern.slf4j.Slf4j;
+
+import javax.servlet.http.HttpServletResponse;
+import java.io.*;
+import java.net.URLEncoder;
+import java.nio.charset.StandardCharsets;
+import java.util.ArrayList;
+import java.util.List;
+import java.util.zip.ZipEntry;
+import java.util.zip.ZipOutputStream;
+
+@Slf4j
+public class FileUtil {
+
+    /**
+     * 写入文件
+     *
+     * @param fileName
+     * @param content
+     */
+    public static boolean writeFile(String fileName, String content) {
+        BufferedWriter bw = null;
+
+        try {
+            File file = new File(fileName);
+            if (!file.exists()) {
+//                fileName = fileName.substring(0, fileName.lastIndexOf("\\"));
+//                File file1 = new File(fileName);
+//                file1.mkdirs();
+                file.createNewFile();
+            }
+
+
+            bw = new BufferedWriter(new FileWriter(file, true));
+
+            String[] list = content.split("\n");
+            for (int i = 0; i < list.length; i++) {
+                bw.write(list[i]);
+                bw.write("\n");
+                if (i % 1000 == 0)
+                    bw.flush();
+            }
+            bw.flush();
+        } catch (Exception e) {
+            log.error("writePowerData", e);
+            return false;
+        } finally {
+            try {
+                bw.close();
+            } catch (IOException e) {
+                e.printStackTrace();
+            }
+        }
+
+        return true;
+    }
+
+    /**
+     * 写入文件
+     *
+     * @param path
+     * @param fileName
+     * @param inputStream
+     */
+    public static void writeFile(String path, String fileName, InputStream inputStream) {
+        OutputStream os = null;
+        try {
+            byte[] bs = new byte[1024];
+            int len;
+
+            File file = new File(path);
+            if (!file.exists()) {
+                file.mkdirs();
+            }
+            os = new FileOutputStream(file.getPath() + File.separator + fileName);
+            // 开始读取
+            while ((len = inputStream.read(bs)) != -1) {
+                os.write(bs, 0, len);
+            }
+
+        } catch (IOException e) {
+            log.error(e.getMessage());
+        } catch (Exception e) {
+            e.printStackTrace();
+            log.error(e.getMessage());
+        } finally {
+            // 完毕,关闭所有链接
+            try {
+                os.close();
+                inputStream.close();
+            } catch (IOException e) {
+                log.error(e.getMessage());
+            }
+        }
+    }
+
+
+    // String -> InputStream
+    public static InputStream convertStringToInputStream(String content) {
+
+        InputStream result = new ByteArrayInputStream(content.getBytes(StandardCharsets.UTF_8));
+        return result;
+
+    }
+
+    /**
+     * 读取文件
+     *
+     * @param fileName
+     * @param isAll    是否读取全部数据
+     * @return
+     */
+    public static List<String> readFile(String fileName, boolean isAll) {
+        List<String> list = new ArrayList<>();
+        BufferedReader reader = null;
+
+        try {
+            File file = new File(fileName);
+            reader = new BufferedReader(new FileReader(file));
+            String content = null;
+            int line = 0;
+            // 一次读入一行,直到读入null为文件结束
+            while ((content = reader.readLine()) != null) {
+                // 显示行号
+                list.add(content);
+                line++;
+                if (!isAll && line == 300)
+                    break;
+            }
+            reader.close();
+        } catch (IOException e) {
+            log.error(e.getMessage());
+        } finally {
+            if (reader != null) {
+                try {
+                    reader.close();
+                } catch (IOException e1) {
+                }
+            }
+        }
+
+        return list;
+    }
+
+
+    /**
+     * 加载文件
+     *
+     * @param fileName
+     * @return
+     */
+    public static void download(String fileName, HttpServletResponse response) {
+        FileInputStream fis = null;
+        BufferedInputStream bis = null;
+        try {
+            // 获取文件
+            File file = new File(fileName);
+            // 清空缓冲区,状态码和响应头(headers)
+            response.reset();
+            // 设置ContentType,响应内容为二进制数据流,编码为utf-8,此处设定的编码是文件内容的编码
+            response.setContentType("application/octet-stream;charset=utf-8");
+            // 以(Content-Disposition: attachment; filename="filename.jpg")格式设定默认文件名,设定utf编码,此处的编码是文件名的编码,使能正确显示中文文件名
+            response.setHeader("Content-Disposition", "attachment;fileName=" + file.getName() + ";filename*=utf-8''" + URLEncoder.encode(file.getName(), "utf-8"));
+
+            // 实现文件下载
+            byte[] buffer = new byte[1024];
+            fis = new FileInputStream(file);
+            bis = new BufferedInputStream(fis);
+            // 获取字节流
+            OutputStream os = response.getOutputStream();
+            int i = bis.read(buffer);
+            while (i != -1) {
+                os.write(buffer, 0, i);
+                i = bis.read(buffer);
+            }
+        } catch (Exception e) {
+            log.error("FileUtil--download", e);
+        } finally {
+            if (bis != null) {
+                try {
+                    bis.close();
+                } catch (IOException e) {
+                    e.printStackTrace();
+                }
+            }
+            if (fis != null) {
+                try {
+                    fis.close();
+                } catch (IOException e) {
+                    e.printStackTrace();
+                }
+            }
+        }
+    }
+
+
+    /**
+     * @describe 压缩多个文件
+     * @author zfc
+     */
+    public static String zipFiles(List<File> srcFiles, File zipFile) {
+        // 判断压缩后的文件存在不,不存在则创建
+        if (!zipFile.exists()) {
+            try {
+                String fileName = zipFile.getAbsolutePath();
+                fileName = fileName.substring(0, fileName.lastIndexOf("\\"));
+                File file1 = new File(fileName);
+                file1.mkdirs();
+                zipFile.createNewFile();
+            } catch (IOException e) {
+                e.printStackTrace();
+            }
+        }
+        // 创建 FileOutputStream 对象
+        FileOutputStream fileOutputStream = null;
+        // 创建 ZipOutputStream
+        ZipOutputStream zipOutputStream = null;
+        // 创建 FileInputStream 对象
+        FileInputStream fileInputStream = null;
+
+        try {
+            // 实例化 FileOutputStream 对象
+            fileOutputStream = new FileOutputStream(zipFile);
+            // 实例化 ZipOutputStream 对象
+            zipOutputStream = new ZipOutputStream(fileOutputStream);
+            // 创建 ZipEntry 对象
+            ZipEntry zipEntry = null;
+            // 遍历源文件数组
+            for (int i = 0; i < srcFiles.size(); i++) {
+                // 将源文件数组中的当前文件读入 FileInputStream 流中
+                fileInputStream = new FileInputStream(srcFiles.get(i));
+                // 实例化 ZipEntry 对象,源文件数组中的当前文件
+                zipEntry = new ZipEntry(srcFiles.get(i).getName());
+                zipOutputStream.putNextEntry(zipEntry);
+                // 该变量记录每次真正读的字节个数
+                int len;
+                // 定义每次读取的字节数组
+                byte[] buffer = new byte[1024];
+                while ((len = fileInputStream.read(buffer)) > 0) {
+                    zipOutputStream.write(buffer, 0, len);
+                }
+            }
+            zipOutputStream.closeEntry();
+            zipOutputStream.close();
+            fileInputStream.close();
+            fileOutputStream.close();
+        } catch (IOException e) {
+            e.printStackTrace();
+        }
+
+        return zipFile.getAbsolutePath();
+    }
+
+    /**
+     * 从文件中获取字符串
+     *
+     * @param path 路径
+     * @return 字符串
+     */
+    public static String getStringFromFile(String path) {
+        BufferedReader bufferedReader = null;
+        File file = new File(path);
+        if (!file.exists()) {
+            return "";
+        }
+        try {
+            bufferedReader = new BufferedReader(new FileReader(file));
+            StringBuilder sb = new StringBuilder();
+            String s = null;
+            while ((s = bufferedReader.readLine()) != null) {
+                sb.append(s);
+            }
+            return sb.toString();
+        } catch (IOException e) {
+            e.printStackTrace();
+        } finally {
+            try {
+                assert bufferedReader != null;
+                bufferedReader.close();
+            } catch (IOException e) {
+                e.printStackTrace();
+            }
+        }
+        return "";
+    }
+}

+ 162 - 0
runeconomy-xk/src/main/java/com/gyee/runeconomy/util/SnowFlakeUtil.java

@@ -0,0 +1,162 @@
+package com.gyee.runeconomy.util;
+
+
+/**
+ * Twitter_Snowflake<br>
+ * SnowFlake的结构如下(每部分用-分开):<br>
+ * 0 - 0000000000 0000000000 0000000000 0000000000 0 - 00000 - 00000 - 000000000000 <br>
+ * 1位标识,由于long基本类型在Java中是带符号的,最高位是符号位,正数是0,负数是1,所以id一般是正数,最高位是0<br>
+ * 41位时间截(毫秒级),注意,41位时间截不是存储当前时间的时间截,而是存储时间截的差值(当前时间截 - 开始时间截)
+ * 得到的值),这里的的开始时间截,一般是我们的id生成器开始使用的时间,由我们程序来指定的(如下下面程序IdWorker类的startTime属性)。41位的时间截,可以使用69年,年T = (1L << 41) / (1000L * 60 * 60 * 24 * 365) = 69<br>
+ * 10位的数据机器位,可以部署在1024个节点,包括5位datacenterId和5位workerId<br>
+ * 12位序列,毫秒内的计数,12位的计数顺序号支持每个节点每毫秒(同一机器,同一时间截)产生4096个ID序号<br>
+ * 加起来刚好64位,为一个Long型。<br>
+ * SnowFlake的优点是,整体上按照时间自增排序,并且整个分布式系统内不会产生ID碰撞(由数据中心ID和机器ID作区分),并且效率较高,经测试,SnowFlake每秒能够产生26万ID左右。
+ */
+public class SnowFlakeUtil {
+
+    // ==============================Fields===========================================
+    /** 开始时间截 (2015-01-01) */
+    private final long twepoch = 1420041600000L;
+
+    /** 机器id所占的位数 */
+    private final long workerIdBits = 5L;
+
+    /** 数据标识id所占的位数 */
+    private final long datacenterIdBits = 5L;
+
+    /** 支持的最大机器id,结果是31 (这个移位算法可以很快的计算出几位二进制数所能表示的最大十进制数) */
+    private final long maxWorkerId = -1L ^ (-1L << workerIdBits);
+
+    /** 支持的最大数据标识id,结果是31 */
+    private final long maxDatacenterId = -1L ^ (-1L << datacenterIdBits);
+
+    /** 序列在id中占的位数 */
+    private final long sequenceBits = 12L;
+
+    /** 机器ID向左移12位 */
+    private final long workerIdShift = sequenceBits;
+
+    /** 数据标识id向左移17位(12+5) */
+    private final long datacenterIdShift = sequenceBits + workerIdBits;
+
+    /** 时间截向左移22位(5+5+12) */
+    private final long timestampLeftShift = sequenceBits + workerIdBits + datacenterIdBits;
+
+    /** 生成序列的掩码,这里为4095 (0b111111111111=0xfff=4095) */
+    private final long sequenceMask = -1L ^ (-1L << sequenceBits);
+
+    /** 工作机器ID(0~31) */
+    private long workerId;
+
+    /** 数据中心ID(0~31) */
+    private long datacenterId;
+
+    /** 毫秒内序列(0~4095) */
+    private long sequence = 0L;
+
+    /** 上次生成ID的时间截 */
+    private long lastTimestamp = -1L;
+
+    //==============================Constructors=====================================
+    /**
+     * 构造函数
+     * @param workerId 工作ID (0~31)
+     * @param datacenterId 数据中心ID (0~31)
+     */
+    public SnowFlakeUtil(long workerId, long datacenterId) {
+        if (workerId > maxWorkerId || workerId < 0) {
+            throw new IllegalArgumentException(String.format("worker Id can't be greater than %d or less than 0", maxWorkerId));
+        }
+        if (datacenterId > maxDatacenterId || datacenterId < 0) {
+            throw new IllegalArgumentException(String.format("datacenter Id can't be greater than %d or less than 0", maxDatacenterId));
+        }
+        this.workerId = workerId;
+        this.datacenterId = datacenterId;
+    }
+
+    // ==============================Methods==========================================
+    /**
+     * 获得下一个ID (该方法是线程安全的)
+     * @return SnowflakeId
+     */
+    public synchronized long nextId() {
+        long timestamp = timeGen();
+
+        //如果当前时间小于上一次ID生成的时间戳,说明系统时钟回退过这个时候应当抛出异常
+        if (timestamp < lastTimestamp) {
+            throw new RuntimeException(
+                    String.format("Clock moved backwards.  Refusing to generate id for %d milliseconds", lastTimestamp - timestamp));
+        }
+
+        //如果是同一时间生成的,则进行毫秒内序列
+        if (lastTimestamp == timestamp) {
+            sequence = (sequence + 1) & sequenceMask;
+            //毫秒内序列溢出
+            if (sequence == 0) {
+                //阻塞到下一个毫秒,获得新的时间戳
+                timestamp = tilNextMillis(lastTimestamp);
+            }
+        }
+        //时间戳改变,毫秒内序列重置
+        else {
+            sequence = 0L;
+        }
+
+        //上次生成ID的时间截
+        lastTimestamp = timestamp;
+
+        //移位并通过或运算拼到一起组成64位的ID
+        return ((timestamp - twepoch) << timestampLeftShift) //
+                | (datacenterId << datacenterIdShift) //
+                | (workerId << workerIdShift) //
+                | sequence;
+    }
+
+    /**
+     * 阻塞到下一个毫秒,直到获得新的时间戳
+     * @param lastTimestamp 上次生成ID的时间截
+     * @return 当前时间戳
+     */
+    protected long tilNextMillis(long lastTimestamp) {
+        long timestamp = timeGen();
+        while (timestamp <= lastTimestamp) {
+            timestamp = timeGen();
+        }
+        return timestamp;
+    }
+
+    /**
+     * 返回以毫秒为单位的当前时间
+     * @return 当前时间(毫秒)
+     */
+    protected long timeGen() {
+        return System.currentTimeMillis();
+    }
+
+
+    private static SnowFlakeUtil idWorker = null;
+
+    public static String generateId() {
+        if (idWorker == null)
+            idWorker = new SnowFlakeUtil(0, 0);
+
+        return String.valueOf(idWorker.nextId());
+//        for (int i = 0; i < 1000; i++) {
+//            long id = idWorker.nextId();
+//            System.out.println(Long.toBinaryString(id));
+//            System.out.println(id);
+//        }
+    }
+    public static Long generateIdL() {
+        if (idWorker == null)
+            idWorker = new SnowFlakeUtil(0, 0);
+
+        return idWorker.nextId();
+//        for (int i = 0; i < 1000; i++) {
+//            long id = idWorker.nextId();
+//            System.out.println(Long.toBinaryString(id));
+//            System.out.println(id);
+//        }
+    }
+}