浏览代码

增加电力交易接口(获取数据、写入调控值),以及获取token接口及系统内鉴权默认7天有效期

xusl 2 月之前
父节点
当前提交
802e820453

+ 171 - 0
cpp-admin/src/main/java/com/cpp/web/controller/common/ExternalInterfaceController.java

@@ -0,0 +1,171 @@
+package com.cpp.web.controller.common;
+
+import cn.hutool.core.date.DateUtil;
+import cn.hutool.core.util.StrUtil;
+import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
+import com.cpp.common.core.domain.R;
+import com.cpp.system.service.ISysConfigService;
+import com.cpp.web.domain.station.ForecastPowerShortTermRegulation;
+import com.cpp.web.domain.station.ForecastPowerShortTermStation;
+import com.cpp.web.dto.DljyReturnDataDto;
+import com.cpp.web.service.datafactory.BaseParsingService;
+import com.cpp.web.service.regulation.TempShortRegulationDfService;
+import com.cpp.web.service.station.ForecastPowerShortTermRegulationService;
+import com.cpp.web.service.station.ForecastPowerShortTermSendService;
+import com.cpp.web.service.station.ForecastPowerShortTermStationService;
+import com.cpp.web.utils.DateTimeUtil;
+import lombok.extern.slf4j.Slf4j;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.web.bind.annotation.GetMapping;
+import org.springframework.web.bind.annotation.PostMapping;
+import org.springframework.web.bind.annotation.RequestMapping;
+import org.springframework.web.bind.annotation.RestController;
+
+import java.util.*;
+import java.util.stream.Collectors;
+
+/**
+ * 对外接口
+ *
+ * @author jy
+ * @since 2025/02/20
+ */
+@RestController
+@RequestMapping("/externalApi")
+@Slf4j
+public class ExternalInterfaceController {
+    @Autowired
+    BaseParsingService baseParsingService;
+    @Autowired
+    ISysConfigService configService;
+    @Autowired
+    ForecastPowerShortTermStationService forecastPowerShortTermStationService;
+    @Autowired
+    ForecastPowerShortTermRegulationService forecastPowerShortTermRegulationService;
+    @Autowired
+    ForecastPowerShortTermSendService forecastPowerShortTermSendService;
+    @Autowired
+    TempShortRegulationDfService tempShortRegulationDfService;
+
+
+    /**
+     * 根据指定日期获取未来10天数据
+     * @Param queryDate格式yyyyMMdd
+     * @return
+     */
+    @GetMapping("/queryForecastData")
+    public R queryForecastData(String stationCode,String genDate) {
+        if (StrUtil.isBlankIfStr(stationCode) || StrUtil.isBlankIfStr(genDate)){
+            return R.fail("访问参数存在空值");
+        }
+        Date date = null;
+        try {
+            // 尝试使用指定的模式解析日期字符串
+            date = DateUtil.parse(genDate, "yyyyMMdd");
+        } catch (Exception e) {
+            // 如果解析失败(抛出了 UtilException 异常),则返回 false
+            return R.fail("日期参数格式不正确");
+        }
+        try {
+            String queryDays = configService.selectConfigByKey("require_dq_day");
+            if (StrUtil.isBlankIfStr(queryDays)) {
+                queryDays = "10";
+            }
+            // 查询站端原始预测数据
+            QueryWrapper ysWrapper = new QueryWrapper();
+            ysWrapper.eq("gen_date", date);
+            ysWrapper.eq("station_code", stationCode);
+            List<ForecastPowerShortTermStation> ysList = forecastPowerShortTermStationService.list(ysWrapper);
+            // 将ysList分组,按时间long类型
+            Map<Long, ForecastPowerShortTermStation> ysMap = ysList.stream()
+                    .collect(Collectors.toMap(
+                            myObject -> myObject.getTime().getTime(),
+                            myObject -> myObject,
+                            (existing, replacement) -> existing
+                    ));
+
+            // 查询站端上报预测数据
+            QueryWrapper sbWrapper = new QueryWrapper();
+            sbWrapper.eq("gen_date", date);
+            sbWrapper.eq("station_code", stationCode);
+            List<ForecastPowerShortTermRegulation> sbList = forecastPowerShortTermRegulationService.list(sbWrapper);
+            Map<Long, ForecastPowerShortTermRegulation> sbMap = sbList.stream()
+                    .collect(Collectors.toMap(
+                            myObject -> myObject.getTime().getTime(),
+                            myObject -> myObject,
+                            (existing, replacement) -> existing
+                    ));
+
+            // 查询中心侧下发调控的短期数据
+            QueryWrapper tkWrapper = new QueryWrapper();
+            tkWrapper.eq("gen_date", date);
+            tkWrapper.eq("station_code", stationCode);
+            List<ForecastPowerShortTermRegulation> tkList = forecastPowerShortTermSendService.list(tkWrapper);
+            Map<Long, ForecastPowerShortTermRegulation> tkMap = tkList.stream()
+                    .collect(Collectors.toMap(
+                            myObject -> myObject.getTime().getTime(),
+                            myObject -> myObject,
+                            (existing, replacement) -> existing
+                    ));
+
+            Long momentTime = 15 * 60 * 1000L; // 15分钟一个时刻
+            long startTime = DateUtil.offsetDay(date, 1).getTime();
+            long endTime = DateTimeUtil.getDayLastTime(DateUtil.offsetDay(date, Integer.parseInt(queryDays)).getTime()).getTime();
+            List<DljyReturnDataDto> dljyReturnDataDtoList = new ArrayList<>();
+            for (Long tempTime = startTime; tempTime <= endTime; tempTime = tempTime + momentTime) {
+                DljyReturnDataDto dljyReturnDataDto = new DljyReturnDataDto();
+                dljyReturnDataDto.setStationCode(stationCode);
+                dljyReturnDataDto.setTime(DateUtil.format(new Date(tempTime), "yyyy-MM-dd HH:mm:ss"));
+                dljyReturnDataDto.setYsData(ysMap.get(tempTime) == null ? "null" : ysMap.get(tempTime).getFpValue().toString());
+                dljyReturnDataDto.setTkData(tkMap.get(tempTime) == null ? "null" : tkMap.get(tempTime).getFpValue().toString());
+                dljyReturnDataDto.setSbData(sbMap.get(tempTime) == null ? "null" : sbMap.get(tempTime).getFpValue().toString());
+                dljyReturnDataDtoList.add(dljyReturnDataDto);
+            }
+            return R.ok(dljyReturnDataDtoList);
+        }
+        catch (Exception e){
+            e.printStackTrace();
+            return R.fail("查询内部错误导致失败!");
+        }
+    }
+
+    /**
+     * 接收电辅系统调控的预测数据
+     * @Param stationCode 场站编号
+     * @Param tkDataJson 调控数据json格式 jsonString = "[{'time':'2025-02-21 14:00:00','value':'15'},{'time':'2025-02-21 14:15:00','value':'30'},{'time':'2025-02-21 14:30:00','value':'7'}]";
+     *
+     * @return
+     */
+    @PostMapping("/reviceDfTkData")
+    public R reviceDfTkData(String stationCode,String tkDataJson) {
+        if (StrUtil.isBlankIfStr(stationCode) || StrUtil.isBlankIfStr(tkDataJson)){
+            return R.fail("访问参数存在空值");
+        }
+        String dqEndTime = configService.selectConfigByKey("dqEndTime");
+        String[] times = dqEndTime.trim().split(":");
+        Calendar calendar = Calendar.getInstance();
+        calendar.setTime(new Date());
+        calendar.set(Calendar.HOUR_OF_DAY, Integer.parseInt(times[0]));
+        calendar.set(Calendar.MINUTE, Integer.parseInt(times[1]));
+        calendar.set(Calendar.SECOND, 0);
+        if (new Date().after(calendar.getTime())){
+            return R.fail("超过今日调控最后时间"+DateUtil.format(calendar.getTime(), "yyyy-MM-dd HH:mm:ss")+",电力交易侧无法调控");
+        }
+        // 验证场站今日是否上传原始数据
+        QueryWrapper ysWrapper = new QueryWrapper();
+        ysWrapper.eq("gen_date", DateTimeUtil.getDayStartTime(new Date().getTime()));
+        ysWrapper.eq("station_code", stationCode);
+        List<ForecastPowerShortTermStation> ysList = forecastPowerShortTermStationService.list(ysWrapper);
+        if (ysList.size()==0){
+            return R.fail("当前站端未上传今日预测数据,电力交易侧无法调控!");
+        }
+
+        try {
+            tempShortRegulationDfService.reviceDfTkData(stationCode,tkDataJson);
+        } catch (Exception e) {
+            log.error("读取电力交易调控数据出错",e);
+            return R.fail(e.getMessage());
+        }
+        return R.ok();
+    }
+}

+ 90 - 33
cpp-admin/src/main/java/com/cpp/web/controller/regulation/DqRegulationController.java

@@ -18,10 +18,7 @@ import com.cpp.web.domain.enums.DataSourcesEnum;
 import com.cpp.web.domain.enums.ForecastTypeEnum;
 import com.cpp.web.domain.enums.RegulationStatusEnum;
 import com.cpp.web.domain.enums.UploadStatusEnum;
-import com.cpp.web.domain.regulation.TempShortRegulation;
-import com.cpp.web.domain.regulation.TempShortRegulationDetail;
-import com.cpp.web.domain.regulation.TempShortUsual;
-import com.cpp.web.domain.regulation.TempShortUsualDetail;
+import com.cpp.web.domain.regulation.*;
 import com.cpp.web.domain.station.ElectricField;
 import com.cpp.web.domain.station.ForecastPowerShortTermRegulation;
 import com.cpp.web.domain.station.ForecastPowerShortTermStation;
@@ -29,10 +26,7 @@ import com.cpp.web.domain.station.InverterStatusData;
 import com.cpp.web.dto.TempShortRegulationDto;
 import com.cpp.web.service.accuracy.AccuracyPassRateService;
 import com.cpp.web.service.cloud.ForecastPowerShortTermCloudService;
-import com.cpp.web.service.regulation.TempShortRegulationDetailService;
-import com.cpp.web.service.regulation.TempShortRegulationService;
-import com.cpp.web.service.regulation.TempShortUsualDetailService;
-import com.cpp.web.service.regulation.TempShortUsualService;
+import com.cpp.web.service.regulation.*;
 import com.cpp.web.service.station.ElectricFieldService;
 import com.cpp.web.service.station.ForecastPowerShortTermRegulationService;
 import com.cpp.web.service.station.ForecastPowerShortTermStationService;
@@ -78,7 +72,8 @@ public class DqRegulationController {
     ForecastPowerShortTermRegulationService forecastPowerShortTermRegulationService;
     @Autowired
     ForecastPowerShortTermCloudService forecastPowerShortTermCloudService;
-
+    @Autowired
+    TempShortRegulationDfService tempShortRegulationDfService;
 
 
     @GetMapping("/queryData")
@@ -150,6 +145,20 @@ public class DqRegulationController {
             List<BigDecimal> refUpList = new ArrayList<>();
             // 参考下限短期
             List<BigDecimal> refDownList = new ArrayList<>();
+            // 获取电力交易调控数据
+            QueryWrapper<TempShortRegulationDf> tempShortRegulationDfQueryWrapper = new QueryWrapper<>();
+            tempShortRegulationDfQueryWrapper.eq("station_code", stationCode);
+            tempShortRegulationDfQueryWrapper.eq("tk_date", DateTimeUtil.getDayStartTime(System.currentTimeMillis()));
+            tempShortRegulationDfQueryWrapper.eq("forecast_date", new Date(time));
+            tempShortRegulationDfQueryWrapper.between("time", new Date(time), new Date(endTime));
+            List<TempShortRegulationDf> tempShortRegulationDfList = tempShortRegulationDfService.list(tempShortRegulationDfQueryWrapper);
+            Map<Long, BigDecimal> dljyTkDataMap = new HashMap<>();
+            for (TempShortRegulationDf tempShortRegulationDf:tempShortRegulationDfList) {
+                dljyTkDataMap.putIfAbsent(tempShortRegulationDf.getTime().getTime(), tempShortRegulationDf.getTkValue());
+            }
+            // 电力交易调控数据
+            List<BigDecimal> dljyTkDataList = new ArrayList<>();
+
             ElectricField electricField = electricFieldService.findByStationCode(stationCode);
             Long momentTime = 15 * 60 * 1000L;
             for (Long tempTime = time; tempTime <= endTime; tempTime = tempTime + momentTime) {
@@ -201,6 +210,13 @@ public class DqRegulationController {
                     listAfter.add(null);
                 }
                 tkDataList.add(listAfter);
+
+                if (dljyTkDataMap.get(tempTime)!=null){
+                    dljyTkDataList.add(dljyTkDataMap.get(tempTime));
+                }
+                else{
+                    dljyTkDataList.add(null);
+                }
             }
             // 原始值
             map.put("ysData",ysList);
@@ -212,9 +228,9 @@ public class DqRegulationController {
             map.put("tempShortRegulationList",tempList);
             // 页面调控曲线数值
             map.put("tkDataList",tkDataList);
-
-
             map.put("electricField",electricField);
+            // 电力交易曲线数值
+            map.put("dljyTkDataList",dljyTkDataList);
 
             return R.ok(map);
         }
@@ -227,6 +243,31 @@ public class DqRegulationController {
     public R updateDqRegulation(@RequestBody List<TempShortRegulationDto> tempShortRegulationDtoList) {
         // 先删除调控明细表中已有的数据
         TempShortRegulationDto tempShortRegulationDto = tempShortRegulationDtoList.get(0);
+        // 调控主表是否存在
+        QueryWrapper<TempShortRegulation> tempShortRegulationQueryWrapper = new QueryWrapper<>();
+        tempShortRegulationQueryWrapper.eq("station_code", tempShortRegulationDto.getStationCode());
+        tempShortRegulationQueryWrapper.eq("forecast_date", tempShortRegulationDto.getForecastDate());
+        tempShortRegulationQueryWrapper.eq("tk_date", DateTimeUtil.getDayStartTime(System.currentTimeMillis()));
+        List<TempShortRegulation> tempShortRegulationList = tempShortRegulationService.list(tempShortRegulationQueryWrapper);
+        LoginUser loginUser = SecurityUtils.getLoginUser();
+        TempShortRegulation tempShortRegulation = null;
+        if (tempShortRegulationList.isEmpty()) {
+            // 不存在就插入一条调控主表
+            tempShortRegulation = new TempShortRegulation();
+            tempShortRegulation.setStationCode(tempShortRegulationDto.getStationCode());
+            tempShortRegulation.setForecastDate(tempShortRegulationDto.getForecastDate());
+            tempShortRegulation.setTkDate(tempShortRegulationDto.getTkDate());
+            tempShortRegulation.setCreateBy(loginUser.getUsername());
+            // 设置未下发
+            tempShortRegulation.setRegulationStatusEnum(RegulationStatusEnum.E2.name());
+            // 设置未回传
+            tempShortRegulation.setUploadStatusEnum(UploadStatusEnum.E3.name());
+            tempShortRegulationService.save(tempShortRegulation);
+        }
+        else{
+            tempShortRegulation = tempShortRegulationList.get(0);
+        }
+
         // 调控的预测日期
         Date forecastDate = tempShortRegulationDto.getForecastDate();
         Date startTime = DateTimeUtil.getDayStartTime(forecastDate.getTime());
@@ -237,26 +278,6 @@ public class DqRegulationController {
         tempShortRegulationDetailQueryWrapper.eq("tk_date", DateTimeUtil.getDayStartTime(System.currentTimeMillis()));
         tempShortRegulationDetailQueryWrapper.between("time", startTime, endTime);
         tempShortRegulationDetailService.remove(tempShortRegulationDetailQueryWrapper);
-        // 删除调控主表
-        QueryWrapper<TempShortRegulation> tempShortRegulationQueryWrapper = new QueryWrapper<>();
-        tempShortRegulationQueryWrapper.eq("station_code", tempShortRegulationDto.getStationCode());
-        tempShortRegulationQueryWrapper.eq("forecast_date", tempShortRegulationDto.getForecastDate());
-        tempShortRegulationQueryWrapper.eq("tk_date", DateTimeUtil.getDayStartTime(System.currentTimeMillis()));
-        tempShortRegulationService.remove(tempShortRegulationQueryWrapper);
-
-        LoginUser loginUser = SecurityUtils.getLoginUser();
-        // 插入调控主表
-        TempShortRegulation tempShortRegulation = new TempShortRegulation();
-        tempShortRegulation.setStationCode(tempShortRegulationDto.getStationCode());
-        tempShortRegulation.setForecastDate(tempShortRegulationDto.getForecastDate());
-        tempShortRegulation.setTkDate(tempShortRegulationDto.getTkDate());
-        tempShortRegulation.setCreateBy(loginUser.getUsername());
-        // 设置未下发
-        tempShortRegulation.setRegulationStatusEnum(RegulationStatusEnum.E2.name());
-        // 设置未回传
-        tempShortRegulation.setUploadStatusEnum(UploadStatusEnum.E3.name());
-        tempShortRegulationService.save(tempShortRegulation);
-
         // 封装新的调控明细插入数据
         List<TempShortRegulationDetail> tempShortRegulationDetailList = new ArrayList<>();
         for (TempShortRegulationDto tempShortRegulationDto1 : tempShortRegulationDtoList) {
@@ -275,8 +296,6 @@ public class DqRegulationController {
             tempShortRegulationDetailList.add(tempShortRegulationDetail);
         }
         tempShortRegulationDetailService.saveBatch(tempShortRegulationDetailList);
-
-
         return R.ok();
     }
 
@@ -476,11 +495,49 @@ public class DqRegulationController {
                 ysLineList.add(tempShortRegulationDetail.getYsValue());
             }
         }
+
+        boolean ysSource = false;
+        if (ysLineList.isEmpty()){
+            ysSource = true;
+        }
+        // 定义电力交易曲线数据
+        QueryWrapper<TempShortRegulationDf> tempShortRegulationDfQueryWrapper = new QueryWrapper<>();
+        tempShortRegulationDfQueryWrapper.eq("station_code", stationCode);
+        tempShortRegulationDfQueryWrapper.eq("tk_date", DateUtil.parse(tkDate, "yyyy-MM-dd"));
+        tempShortRegulationDfQueryWrapper.eq("forecast_date", DateUtil.parse(forecastDate, "yyyy-MM-dd"));
+        List<TempShortRegulationDf> tempShortRegulationDfList = tempShortRegulationDfService.list(tempShortRegulationDfQueryWrapper);
+        List<BigDecimal> dljyLineList = new ArrayList<>();
+        if (tempShortRegulationDfList.size()>0){
+            // 先按预测时间排序
+            tempShortRegulationDfList.sort(Comparator.comparing(TempShortRegulationDf::getTime));
+            for (TempShortRegulationDf tempShortRegulationDf:tempShortRegulationDfList){
+                // 电力交易调控曲线数据封装
+                dljyLineList.add(tempShortRegulationDf.getTkValue());
+                if (ysSource){
+                    // 由于电力交易进行调控,但集中侧没有调控,所以为了页面展示效果,将原始、集中侧调控的列表和曲线默认赋值
+                    ysLineList.add(tempShortRegulationDf.getYsValue());
+                    // 调控曲线数据封装
+                    tkLineList.add(tempShortRegulationDf.getYsValue());
+                    TempShortRegulationDto tempShortRegulationDto = new TempShortRegulationDto();
+                    tempShortRegulationDto.setTime(DateUtils.parseDateToStr("HH:mm",tempShortRegulationDf.getTime()));
+                    tempShortRegulationDto.setForecastDate(tempShortRegulationDf.getForecastDate());
+                    tempShortRegulationDto.setTkDate(tempShortRegulationDf.getTkDate());
+                    tempShortRegulationDto.setYsValue(tempShortRegulationDf.getYsValue());
+                    tempShortRegulationDto.setTkValue(tempShortRegulationDf.getYsValue());
+                    tempShortRegulationDto.setSz(new BigDecimal("0"));
+                    tempShortRegulationDto.setXs(new BigDecimal("1"));
+                    tempShortRegulationDto.setStationCode(stationCode);
+                    detailList.add(tempShortRegulationDto);
+                }
+            }
+        }
+
         Map<String, Object> map = new HashMap<>();
         // 弹出框明细列表
         map.put("detailList",detailList);
         map.put("tkLineList",tkLineList);
         map.put("ysLineList",ysLineList);
+        map.put("dljyLineList",dljyLineList);
         // 获取上报曲线数据
         long time = DateUtil.parse(forecastDate, "yyyy-MM-dd").getTime();
         Date startForecastTime = DateTimeUtil.getDayStartTime(time);

+ 14 - 0
cpp-admin/src/main/java/com/cpp/web/controller/system/SysLoginController.java

@@ -83,4 +83,18 @@ public class SysLoginController
         List<SysMenu> menus = menuService.selectMenuTreeByUserId(userId);
         return AjaxResult.success(menuService.buildMenus(menus));
     }
+
+    /**
+     * 用户名密码换取token
+     * @return 结果
+     */
+    @GetMapping("/exchangeForToken")
+    public AjaxResult exchangeForToken(String username, String password)
+    {
+        AjaxResult ajax = AjaxResult.success();
+        // 生成令牌
+        String token = loginService.exchangeForToken(username, password);
+        ajax.put(Constants.TOKEN, token);
+        return ajax;
+    }
 }

+ 81 - 0
cpp-admin/src/main/java/com/cpp/web/domain/regulation/TempShortRegulationDf.java

@@ -0,0 +1,81 @@
+package com.cpp.web.domain.regulation;
+
+import com.baomidou.mybatisplus.annotation.FieldFill;
+import com.baomidou.mybatisplus.annotation.TableField;
+import com.baomidou.mybatisplus.annotation.TableName;
+import com.cpp.web.domain.BaseCppEntity;
+import io.swagger.annotations.ApiModel;
+import io.swagger.annotations.ApiModelProperty;
+import lombok.Data;
+import lombok.EqualsAndHashCode;
+
+import javax.validation.constraints.Digits;
+import java.math.BigDecimal;
+import java.util.Date;
+
+/**
+ * 临时短期电辅系统传来的调控明细
+ *
+ * @author tl
+ * @date 2024-09-23 15:28:33
+ */
+@Data
+@TableName("cpp_temp_short_regulation_df")
+@EqualsAndHashCode(callSuper = true)
+@ApiModel(value = "cpp_temp_short_regulation_df")
+public class TempShortRegulationDf extends BaseCppEntity {
+
+    @ApiModelProperty(value = "调控表主键ID")
+    private Long regulationId;
+
+    /**
+     * 预测时间
+     */
+    @ApiModelProperty(value = "预测值时间")
+    private Date time;
+
+
+    /**
+     * 原始值
+     */
+    @ApiModelProperty(value = "原始值")
+    @Digits(integer = 10, fraction = 2)
+    private BigDecimal ysValue = new BigDecimal(-99);
+
+    /**
+     * 调控值
+     */
+    @ApiModelProperty(value = "调控值")
+    @Digits(integer = 10, fraction = 2)
+    private BigDecimal tkValue = new BigDecimal(-99);
+    /**
+     * 调控的预测日期
+     */
+    @ApiModelProperty(value = "调控日期")
+    private Date forecastDate;
+
+    /**
+     * 调控日
+     */
+    @ApiModelProperty(value = "调控日期")
+    private Date tkDate;
+
+    /**
+     * 数值
+     */
+    @ApiModelProperty(value = "数值")
+    @Digits(integer = 10, fraction = 2)
+    private BigDecimal sz = new BigDecimal(-99);
+
+    /**
+     * 系数
+     */
+    @ApiModelProperty(value = "系数")
+    @Digits(integer = 10, fraction = 2)
+    private BigDecimal xs = new BigDecimal(-99);
+
+    /** 创建者 */
+    @TableField(value = "create_by" , fill = FieldFill.INSERT)
+    private String createBy;
+
+}

+ 5 - 1
cpp-admin/src/main/java/com/cpp/web/domain/station/ForecastPowerShortTermSend.java

@@ -24,6 +24,10 @@ import java.util.Date;
 @ApiModel(value = "cpp_forecast_power_short_term_send")
 public class ForecastPowerShortTermSend extends BaseForecastEntity {
 
-
+    /**
+     * 生成日期
+     */
+    @ApiModelProperty(value = "生成日期")
+    private Date genDate;
 
 }

+ 23 - 0
cpp-admin/src/main/java/com/cpp/web/dto/DljyReturnDataDto.java

@@ -0,0 +1,23 @@
+package com.cpp.web.dto;
+
+import lombok.Data;
+
+/**
+ * 电力交易返回数据DTO
+ *
+ * @author jy
+ * @since 2025/02/21
+ */
+@Data
+public class DljyReturnDataDto {
+    // 场站编号
+    String stationCode;
+    // 预测时间
+    String time;
+    // 原始值
+    String ysData;
+    // 调控值
+    String tkData;
+    // 上报值
+    String sbData;
+}

+ 17 - 0
cpp-admin/src/main/java/com/cpp/web/mapper/regulation/TempShortRegulationDfMapper.java

@@ -0,0 +1,17 @@
+package com.cpp.web.mapper.regulation;
+
+
+import com.baomidou.mybatisplus.core.mapper.BaseMapper;
+import com.cpp.web.domain.regulation.TempShortRegulationDf;
+import org.apache.ibatis.annotations.Mapper;
+
+/**
+ * mapper
+ *
+ * @author xsl
+ * @date 2022-05-11 09:47:21
+ */
+@Mapper
+public interface TempShortRegulationDfMapper extends BaseMapper<TempShortRegulationDf> {
+
+}

+ 14 - 0
cpp-admin/src/main/java/com/cpp/web/service/regulation/TempShortRegulationDfService.java

@@ -0,0 +1,14 @@
+package com.cpp.web.service.regulation;
+
+import com.baomidou.mybatisplus.extension.service.IService;
+import com.cpp.web.domain.regulation.TempShortRegulationDf;
+
+/**
+ * cpp_electric_field
+ *
+ * @author tl
+ * @date 2024-09-23 15:28:33
+ */
+public interface TempShortRegulationDfService extends IService<TempShortRegulationDf> {
+    void reviceDfTkData(String stationCode,String tkDataJson)throws Exception;
+}

+ 170 - 0
cpp-admin/src/main/java/com/cpp/web/service/regulation/impl/TempShortRegulationDfServiceImpl.java

@@ -0,0 +1,170 @@
+package com.cpp.web.service.regulation.impl;
+
+import cn.hutool.core.date.DatePattern;
+import cn.hutool.core.date.DateUtil;
+import cn.hutool.json.JSONArray;
+import cn.hutool.json.JSONObject;
+import cn.hutool.json.JSONUtil;
+import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
+import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
+import com.cpp.web.domain.enums.RegulationStatusEnum;
+import com.cpp.web.domain.enums.UploadStatusEnum;
+import com.cpp.web.domain.regulation.TempShortRegulation;
+import com.cpp.web.domain.regulation.TempShortRegulationDf;
+import com.cpp.web.domain.station.ForecastPowerShortTermStation;
+import com.cpp.web.mapper.regulation.TempShortRegulationDfMapper;
+import com.cpp.web.service.regulation.TempShortRegulationDfService;
+import com.cpp.web.service.regulation.TempShortRegulationService;
+import com.cpp.web.service.station.ForecastPowerShortTermStationService;
+import com.cpp.web.utils.DateTimeUtil;
+import lombok.RequiredArgsConstructor;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.stereotype.Service;
+import org.springframework.transaction.annotation.Propagation;
+import org.springframework.transaction.annotation.Transactional;
+
+import java.math.BigDecimal;
+import java.util.*;
+import java.util.stream.Collectors;
+
+
+/**
+ * cpp_electric_field
+ *
+ * @author tl
+ * @date 2024-09-23 15:28:33
+ */
+@Service
+@RequiredArgsConstructor
+public class TempShortRegulationDfServiceImpl extends ServiceImpl<TempShortRegulationDfMapper, TempShortRegulationDf> implements TempShortRegulationDfService {
+
+    @Autowired
+    ForecastPowerShortTermStationService forecastPowerShortTermStationService;
+    @Autowired
+    TempShortRegulationService tempShortRegulationService;
+
+
+    @Transactional(propagation = Propagation.REQUIRED, rollbackFor = Exception.class)
+    public void reviceDfTkData(String stationCode, String tkDataJson) throws Exception {
+
+        Set setDay = new HashSet<>();
+        Map<Long, BigDecimal> dfMap = new HashMap();
+        try {
+            // 使用Hutool的JSONUtil解析JSON字符串为JSONArray
+            JSONArray jsonArray = JSONUtil.parseArray(tkDataJson);
+            // 遍历JSONArray,统计出涉及到哪天被调控
+            for (int i = 0; i < jsonArray.size(); i++) {
+                // 获取每个JSONObject
+                JSONObject jsonObject = jsonArray.getJSONObject(i);
+                // 获取time和value字段的值
+                String time = jsonObject.getStr("time");
+                String formatDate = DateUtil.format(DateUtil.parse(time), "yyyy-MM-dd");
+                setDay.add(formatDate);
+                String value = jsonObject.getStr("value");
+                dfMap.put(DateUtil.parse(time).getTime(), new BigDecimal(value));
+            }
+        } catch (Exception e) {
+            e.printStackTrace();
+            throw new Exception("解析json串失败!");
+        }
+
+
+        // 获取短期原始数据
+        List<String> dayList = new ArrayList<>(setDay);
+        String today = DateUtil.format(new Date(), "yyyy-MM-dd");
+        for (String str:dayList){
+            // 判断调控的时间必须要大于今日
+            if (str.compareTo(today)<=0){
+                throw new Exception("调控的时间要从明日开始");
+            }
+        }
+
+        // 对List进行排序
+        Collections.sort(dayList);
+        // 获取排序后的第一和最后一个元素
+        String firstElement = dayList.get(0);
+        String lastElement = dayList.get(dayList.size() - 1);
+        Date beginDate = DateTimeUtil.getDayStartTime(DateUtil.parse(firstElement, "yyyy-MM-dd").getTime());
+        Date endDate = DateTimeUtil.getDayLastTime(DateUtil.parse(lastElement, "yyyy-MM-dd").getTime());
+        // 查询短期原始数据
+        List<ForecastPowerShortTermStation> forecastPowerShortTermStationList = forecastPowerShortTermStationService.findByForecastTimeBetweenAndStationCode(beginDate, endDate, stationCode);
+
+
+        Iterator<String> iterator = setDay.iterator();
+        while (iterator.hasNext()) {
+            String day = iterator.next();
+            Date forecastDate = DateUtil.parse(day, "yyyy-MM-dd");
+            Date tkDate = DateTimeUtil.getDayStartTime(System.currentTimeMillis());
+            // 调控主表是否存在
+            QueryWrapper<TempShortRegulation> tempShortRegulationQueryWrapper = new QueryWrapper<>();
+            tempShortRegulationQueryWrapper.eq("station_code", stationCode);
+            tempShortRegulationQueryWrapper.eq("forecast_date", forecastDate);
+            tempShortRegulationQueryWrapper.eq("tk_date", tkDate);
+            List<TempShortRegulation> tempShortRegulationList = tempShortRegulationService.list(tempShortRegulationQueryWrapper);
+            TempShortRegulation tempShortRegulation = null;
+            if (tempShortRegulationList.isEmpty()) {
+                // 不存在就插入一条调控主表
+                tempShortRegulation = new TempShortRegulation();
+                tempShortRegulation.setStationCode(stationCode);
+                tempShortRegulation.setForecastDate(DateUtil.parse(day, "yyyy-MM-dd"));
+                tempShortRegulation.setTkDate(DateTimeUtil.getDayStartTime(System.currentTimeMillis()));
+                tempShortRegulation.setCreateBy("电力交易");
+                // 设置未下发
+                tempShortRegulation.setRegulationStatusEnum(RegulationStatusEnum.E2.name());
+                // 设置未回传
+                tempShortRegulation.setUploadStatusEnum(UploadStatusEnum.E3.name());
+                tempShortRegulationService.save(tempShortRegulation);
+            } else {
+                tempShortRegulation = tempShortRegulationList.get(0);
+            }
+
+            int howLongAgo = DateTimeUtil.getDaysBetweenTwoDate(System.currentTimeMillis(), forecastDate.getTime());
+            // 对电力交易的调控明细查找
+            QueryWrapper<TempShortRegulationDf> tempShortRegulationDfQueryWrapper = new QueryWrapper<>();
+            tempShortRegulationDfQueryWrapper.eq("station_code", stationCode);
+            tempShortRegulationDfQueryWrapper.eq("forecast_date", forecastDate);
+            tempShortRegulationDfQueryWrapper.eq("tk_date", tkDate);
+            List<TempShortRegulationDf> tempShortRegulationDfList = this.list(tempShortRegulationDfQueryWrapper);
+            if (tempShortRegulationDfList.isEmpty()) {
+                // 过滤出短期原始数据
+                List<ForecastPowerShortTermStation> filterList = forecastPowerShortTermStationList.stream().filter(
+                        forecastPowerShortTermStation -> forecastPowerShortTermStation.getForecastHowLongAgo().intValue() == howLongAgo && DateUtil.format(forecastPowerShortTermStation.getTime(), "yyyy-MM-dd").equals(day)).collect(Collectors.toList());
+
+                // 不存在就插入明细表
+                List<TempShortRegulationDf> newDfList = new ArrayList<>();
+                for (ForecastPowerShortTermStation forecastPowerShortTermStation : filterList) {
+                    TempShortRegulationDf tempShortRegulationDf = new TempShortRegulationDf();
+                    tempShortRegulationDf.setStationCode(stationCode);
+                    tempShortRegulationDf.setForecastDate(forecastDate);
+                    tempShortRegulationDf.setTkDate(tkDate);
+                    tempShortRegulationDf.setTime(forecastPowerShortTermStation.getTime());
+                    tempShortRegulationDf.setRegulationId(tempShortRegulation.getId());
+
+                    if (dfMap.get(forecastPowerShortTermStation.getTime().getTime()) == null) {
+                        tempShortRegulationDf.setTkValue(forecastPowerShortTermStation.getFpValue());
+                    } else {
+                        tempShortRegulationDf.setTkValue(dfMap.get(forecastPowerShortTermStation.getTime().getTime()));
+                    }
+
+                    tempShortRegulationDf.setYsValue(forecastPowerShortTermStation.getFpValue());
+                    tempShortRegulationDf.setXs(new BigDecimal("1"));
+                    //数值=调控值-(原始值*系数)
+                    tempShortRegulationDf.setSz(tempShortRegulationDf.getTkValue().subtract(tempShortRegulationDf.getYsValue()));
+                    tempShortRegulationDf.setCreateBy("电力交易");
+                    newDfList.add(tempShortRegulationDf);
+                }
+                this.saveBatch(newDfList);
+            } else {
+                // 将新来的数据更新到已有的点位上
+                for (TempShortRegulationDf tempShortRegulationDf : tempShortRegulationDfList) {
+                    if (dfMap.get(tempShortRegulationDf.getTime().getTime()) != null) {
+                        tempShortRegulationDf.setTkValue(dfMap.get(tempShortRegulationDf.getTime().getTime()));
+                        //数值=调控值-(原始值*系数)
+                        tempShortRegulationDf.setSz(tempShortRegulationDf.getTkValue().subtract(tempShortRegulationDf.getYsValue()));
+                    }
+                }
+                this.updateBatchById(tempShortRegulationDfList);
+            }
+        }
+    }
+}

+ 13 - 0
cpp-common/src/main/java/com/cpp/common/core/domain/model/LoginUser.java

@@ -71,6 +71,19 @@ public class LoginUser implements UserDetails
      */
     private SysUser user;
 
+    public String getSystemType() {
+        return systemType;
+    }
+
+    public void setSystemType(String systemType) {
+        this.systemType = systemType;
+    }
+
+    /**
+     * 系统类型
+     */
+    private String systemType;
+
     public LoginUser()
     {
     }

+ 1 - 1
cpp-framework/src/main/java/com/cpp/framework/config/SecurityConfig.java

@@ -108,7 +108,7 @@ public class SecurityConfig {
                 .authorizeHttpRequests((requests) -> {
                     permitAllUrl.getUrls().forEach(url -> requests.antMatchers(url).permitAll());
                     // 对于登录login 注册register 验证码captchaImage 允许匿名访问
-                    requests.antMatchers("/login", "/register", "/captchaImage").permitAll()
+                    requests.antMatchers("/login","/exchangeForToken", "/register", "/captchaImage").permitAll()
                             // 静态资源,可匿名访问
                             .antMatchers(HttpMethod.GET, "/", "/*.html", "/**/*.html", "/**/*.css", "/**/*.js", "/profile/**", "/static/**", "/index", "/windy").permitAll()
 

+ 21 - 4
cpp-framework/src/main/java/com/cpp/framework/security/filter/JwtAuthenticationTokenFilter.java

@@ -34,10 +34,27 @@ public class JwtAuthenticationTokenFilter extends OncePerRequestFilter
         LoginUser loginUser = tokenService.getLoginUser(request);
         if (StringUtils.isNotNull(loginUser) && StringUtils.isNull(SecurityUtils.getAuthentication()))
         {
-            tokenService.verifyToken(loginUser);
-            UsernamePasswordAuthenticationToken authenticationToken = new UsernamePasswordAuthenticationToken(loginUser, null, loginUser.getAuthorities());
-            authenticationToken.setDetails(new WebAuthenticationDetailsSource().buildDetails(request));
-            SecurityContextHolder.getContext().setAuthentication(authenticationToken);
+            if (!"DF".equals(loginUser.getSystemType())){
+                tokenService.verifyToken(loginUser);
+                UsernamePasswordAuthenticationToken authenticationToken = new UsernamePasswordAuthenticationToken(loginUser, null, loginUser.getAuthorities());
+                authenticationToken.setDetails(new WebAuthenticationDetailsSource().buildDetails(request));
+                SecurityContextHolder.getContext().setAuthentication(authenticationToken);
+            }
+            else{
+                // 对外接口用户鉴别访问路径
+                String path = "";
+                if (request.getRequestURI().endsWith("/")){
+                    path = request.getRequestURI().substring(0,request.getRequestURI().length()-1);
+                }
+                else {
+                    path = request.getRequestURI();
+                }
+                if (path.equals("/externalApi/queryForecastData") || path.equals("/externalApi/reviceDfTkData")){
+                    UsernamePasswordAuthenticationToken authenticationToken = new UsernamePasswordAuthenticationToken(loginUser, null, loginUser.getAuthorities());
+                    authenticationToken.setDetails(new WebAuthenticationDetailsSource().buildDetails(request));
+                    SecurityContextHolder.getContext().setAuthentication(authenticationToken);
+                }
+            }
         }
         chain.doFilter(request, response);
     }

+ 42 - 0
cpp-framework/src/main/java/com/cpp/framework/web/service/SysLoginService.java

@@ -186,4 +186,46 @@ public class SysLoginService
         sysUser.setLoginDate(DateUtils.getNowDate());
         userService.updateUserProfile(sysUser);
     }
+
+    /**
+     * 换取token
+     *
+     * @param username 用户名
+     * @param password 密码
+     * @return 结果
+     */
+    public String exchangeForToken(String username, String password)
+    {
+        // 登录前置校验
+        loginPreCheck(username, password);
+        // 用户验证
+        Authentication authentication = null;
+        try
+        {
+            UsernamePasswordAuthenticationToken authenticationToken = new UsernamePasswordAuthenticationToken(username, password);
+            AuthenticationContextHolder.setContext(authenticationToken);
+            // 该方法会去调用UserDetailsServiceImpl.loadUserByUsername
+            authentication = authenticationManager.authenticate(authenticationToken);
+        }
+        catch (Exception e)
+        {
+            if (e instanceof BadCredentialsException)
+            {
+                AsyncManager.me().execute(AsyncFactory.recordLogininfor(username, Constants.LOGIN_FAIL, MessageUtils.message("user.password.not.match")));
+                throw new UserPasswordNotMatchException();
+            }
+            else
+            {
+                AsyncManager.me().execute(AsyncFactory.recordLogininfor(username, Constants.LOGIN_FAIL, e.getMessage()));
+                throw new ServiceException(e.getMessage());
+            }
+        }
+        finally
+        {
+            AuthenticationContextHolder.clearContext();
+        }
+        LoginUser loginUser = (LoginUser) authentication.getPrincipal();
+        // 生成token
+        return tokenService.createDljyToken(loginUser);
+    }
 }

+ 27 - 0
cpp-framework/src/main/java/com/cpp/framework/web/service/TokenService.java

@@ -1,7 +1,9 @@
 package com.cpp.framework.web.service;
 
 import java.util.HashMap;
+import java.util.HashSet;
 import java.util.Map;
+import java.util.Set;
 import java.util.concurrent.TimeUnit;
 import javax.servlet.http.HttpServletRequest;
 
@@ -126,6 +128,31 @@ public class TokenService
     }
 
     /**
+     * 创建电力交易令牌
+     *
+     * @param loginUser 用户信息
+     * @return 令牌
+     */
+    public String createDljyToken(LoginUser loginUser)
+    {
+        String token = IdUtils.fastUUID();
+        loginUser.setToken(token);
+        loginUser.setSystemType("DF");
+        Set<String> perms = new HashSet<String>();
+        perms.add("*:*:*");
+        loginUser.setPermissions(perms);
+//        loginUser.setLoginTime(System.currentTimeMillis());
+//        loginUser.setExpireTime(loginUser.getLoginTime() + expireTime * MILLIS_MINUTE);
+        // 根据uuid将loginUser缓存
+        String userKey = getTokenKey(loginUser.getToken());
+        LocalCache.set(userKey, loginUser, 1000 * 60 * 60 * 24 * 7);
+
+        Map<String, Object> claims = new HashMap<>();
+        claims.put(Constants.LOGIN_USER_KEY, token);
+        return createToken(claims);
+    }
+
+    /**
      * 验证令牌有效期,相差不足20分钟,自动刷新缓存
      *
      * @param loginUser

+ 29 - 1
cpp-ui/src/views/regulation/dqRegulation/index.vue

@@ -313,6 +313,7 @@ export default {
       symbolSize: 8,
       capacity: '',
       tkData: [],
+      dljyTkData: [],
       tableData: [],
       hoursArray: [],
       chart: null,
@@ -348,7 +349,7 @@ export default {
           itemWidth: 14,
           itemHeight: 5,
           itemGap: 13,
-          data: ['原始值', '调控值', '参考值上限', '参考值下限'],
+          data: ['原始值', '调控值', '参考值上限', '参考值下限','电力交易值'],
           // right: '4%',
           right: 0,
           textStyle: {
@@ -360,6 +361,7 @@ export default {
             '调控值': true,
             '参考值上限': true,
             '参考值下限': true,
+            '电力交易值': true,
           }
         },
         dataZoom: [{
@@ -484,6 +486,28 @@ export default {
             },
             data: this.refDownData
           },
+            {
+                name: '电力交易值',
+                type: 'line',
+                smooth: true,
+                symbol: 'circle',
+                connectNulls: true,
+                symbolSize: 5,
+                showSymbol: false,
+                lineStyle: {
+                    normal: {
+                        width: 2,
+                        type: 'dashed'   //设置线条类型
+                    }
+                },
+                itemStyle: {
+                    normal: {
+                        color: 'rgb(219,211,50)',
+                        borderWidth: 12
+                    }
+                },
+                data: this.dljyTkData
+            },
         ]
       }
     }
@@ -822,6 +846,7 @@ export default {
         this.refUpData = response.data.refUpData
         this.refDownData = response.data.refDownData
         this.tkData = response.data.tkDataList
+        this.dljyTkData = response.data.dljyTkDataList
         this.draData()
         this.loading = false
       }).catch(() => {
@@ -830,11 +855,13 @@ export default {
         this.refUpData = []
         this.refDownData = []
         this.tkData = []
+        this.dljyTkData = []
         this.chart.clear()
         this.chartOption.series[0].data = this.ysData
         this.chartOption.series[1].data = this.tkData
         this.chartOption.series[2].data = this.refUpData
         this.chartOption.series[3].data = this.refDownData
+        this.chartOption.series[4].data = this.dljyTkData
         this.chart.setOption(this.chartOption)
         this.loading = false
       });
@@ -846,6 +873,7 @@ export default {
       this.chartOption.series[1].data = this.tkData
       this.chartOption.series[2].data = this.refUpData
       this.chartOption.series[3].data = this.refDownData
+      this.chartOption.series[4].data = this.dljyTkData
 
       let myChart = this.chart
       let cap = this.capacity

+ 32 - 7
cpp-ui/src/views/regulation/dqRegulationRecord/index.vue

@@ -212,16 +212,17 @@ export default {
           itemWidth: 14,
           itemHeight: 5,
           itemGap: 13,
-          data: ['原始曲线', '调控曲线','上报曲线'],
+          data: ['原始值', '调控值','上报值','电力交易值'],
           right: '4%',
           textStyle: {
             fontSize: 12,
             // color: this.lineColor
           },
           selected: {
-            '原始曲线': true,
-            '调控曲线': true,
-            '上报曲线': true,
+            '原始值': true,
+            '调控值': true,
+            '上报值': true,
+            '电力交易值': true,
           }
         },
         dataZoom: [{
@@ -258,7 +259,7 @@ export default {
           }
         }],
         series: [{
-          name: '原始曲线',
+          name: '原始',
           type: 'line',
           smooth: true,
           symbol: 'circle',
@@ -280,7 +281,7 @@ export default {
           data: []
         },
           {
-            name: '调控曲线',
+            name: '调控',
             type: 'line',
             showSymbol: false,
             smooth: true,
@@ -302,7 +303,7 @@ export default {
             data: []
           },
           {
-            name: '上报曲线',
+            name: '上报',
             type: 'line',
             showSymbol: false,
             smooth: true,
@@ -323,6 +324,28 @@ export default {
             },
             data: []
           },
+          {
+            name: '电力交易值',
+            type: 'line',
+            showSymbol: false,
+            smooth: true,
+            symbol: 'circle',
+            symbolSize: 5,
+            connectNulls: true,
+            lineStyle: {
+              normal: {
+                color: 'rgb(219,211,50)',
+                width: 2
+              }
+            },
+            itemStyle: {
+              normal: {
+                color: 'rgb(219,211,50)',
+                borderWidth: 50
+              }
+            },
+            data: []
+          },
         ]
       }
     }
@@ -351,6 +374,7 @@ export default {
       this.chartOption.series[0].data = []
       this.chartOption.series[1].data = []
       this.chartOption.series[2].data = []
+      this.chartOption.series[3].data = []
       this.chart.setOption(this.chartOption)
       this.detailOpen = false
     },
@@ -377,6 +401,7 @@ export default {
         this.chartOption.series[0].data = response.data.ysLineList
         this.chartOption.series[1].data = response.data.tkLineList
         this.chartOption.series[2].data = response.data.sbLineList
+        this.chartOption.series[3].data = response.data.dljyLineList
         this.chartOption.yAxis[0].max = response.data.electricField.capacity
         if (!this.chart) {
           this.chart = echarts.init(document.getElementById('tkcharts'), 'dark')