1.新能源专项分析代码优化

2.迁移相关代码算法
This commit is contained in:
wr
2025-04-03 16:02:45 +08:00
parent 47a4f73518
commit 25ad24deb9
22 changed files with 248 additions and 1409 deletions

View File

@@ -1,54 +0,0 @@
package com.njcn.prepare.harmonic.controller.event;
import com.njcn.common.pojo.annotation.OperateInfo;
import com.njcn.common.pojo.constant.OperateType;
import com.njcn.common.pojo.enums.common.LogEnum;
import com.njcn.common.pojo.enums.response.CommonResponseEnum;
import com.njcn.common.pojo.response.HttpResult;
import com.njcn.common.utils.HttpResultUtil;
import com.njcn.harmonic.pojo.vo.PowerStatisticsTargetVO;
import com.njcn.prepare.harmonic.pojo.param.RActivePowerRangeParam;
import com.njcn.prepare.harmonic.pojo.po.RActivePowerRangePO;
import com.njcn.prepare.harmonic.service.mysql.event.RActivePowerRangeService;
import com.njcn.web.controller.BaseController;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiOperation;
import lombok.AllArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.validation.annotation.Validated;
import org.springframework.web.bind.annotation.*;
import java.util.List;
/**
* 有功功率趋势 前端控制器
* @author guofeihu
* @date 2024/8/21
*/
@Validated
@Slf4j
@RestController
@RequestMapping("/rActivePowerRange")
@Api(tags = "有功功率趋势")
@AllArgsConstructor
public class RActivePowerRangeController extends BaseController {
private final RActivePowerRangeService rActivePowerRangeService;
@OperateInfo(info = LogEnum.BUSINESS_COMMON,operateType = OperateType.ADD)
@PostMapping("/record")
@ApiOperation("有功功率趋势记录(用于定时任务)")
public HttpResult<List<PowerStatisticsTargetVO>> record(@RequestBody(required = false) RActivePowerRangeParam rActivePowerRangeParam) {
String methodDescribe = getMethodDescribe("record");
List<PowerStatisticsTargetVO> powerStatisticsTargetVOS = rActivePowerRangeService.record(rActivePowerRangeParam);
return HttpResultUtil.assembleCommonResponseResult(CommonResponseEnum.SUCCESS, powerStatisticsTargetVOS, methodDescribe);
}
@OperateInfo(info = LogEnum.BUSINESS_COMMON,operateType = OperateType.QUERY)
@GetMapping("/getDataByLineId")
@ApiOperation("根据监测点ID及时间获取有功功率趋势")
public HttpResult<RActivePowerRangePO> getDataByLineId(@RequestParam("lineId") String lineId,@RequestParam("startTime") String startTime,@RequestParam("endTime") String endTime) {
String methodDescribe = getMethodDescribe("getDataByLineId");
return HttpResultUtil.assembleCommonResponseResult(CommonResponseEnum.SUCCESS, rActivePowerRangeService.getDataByLineId(lineId,startTime,endTime), methodDescribe);
}
}

View File

@@ -1,64 +0,0 @@
package com.njcn.prepare.harmonic.controller.event;
import com.njcn.common.pojo.annotation.OperateInfo;
import com.njcn.common.pojo.constant.OperateType;
import com.njcn.common.pojo.enums.common.LogEnum;
import com.njcn.common.pojo.enums.response.CommonResponseEnum;
import com.njcn.common.pojo.response.HttpResult;
import com.njcn.common.utils.HttpResultUtil;
import com.njcn.prepare.harmonic.pojo.param.SpThroughParam;
import com.njcn.prepare.harmonic.pojo.vo.SpThroughVO;
import com.njcn.prepare.harmonic.service.mysql.event.SpThroughService;
import com.njcn.web.controller.BaseController;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiOperation;
import lombok.AllArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.validation.annotation.Validated;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import java.util.List;
/**
* 高低电压穿越 前端控制器
* @author guofeihu
* @date 2024/8/21
*/
@Validated
@Slf4j
@RestController
@RequestMapping("/spThrough")
@Api(tags = "高低电压穿越")
@AllArgsConstructor
public class SpThroughController extends BaseController {
private final SpThroughService spThroughService;
@OperateInfo(info = LogEnum.BUSINESS_COMMON,operateType = OperateType.ADD)
@PostMapping("/record")
@ApiOperation("高低电压穿越记录(用于定时任务)")
public HttpResult<Boolean> record() {
String methodDescribe = getMethodDescribe("record");
spThroughService.record();
return HttpResultUtil.assembleCommonResponseResult(CommonResponseEnum.SUCCESS, null, methodDescribe);
}
@OperateInfo(info = LogEnum.BUSINESS_COMMON,operateType = OperateType.QUERY)
@PostMapping("/getDataByEventIds")
@ApiOperation("根据事件ID集合及能源站类型获取高低电压穿越次数")
public HttpResult<SpThroughVO> getDataByEventIds(@RequestBody SpThroughParam spThroughParam) {
String methodDescribe = getMethodDescribe("getDataByEventIds");
return HttpResultUtil.assembleCommonResponseResult(CommonResponseEnum.SUCCESS, spThroughService.getDataByEventIds(spThroughParam), methodDescribe);
}
@OperateInfo(info = LogEnum.BUSINESS_COMMON,operateType = OperateType.QUERY)
@PostMapping("/formatEventIds")
@ApiOperation("根据原有的事件集合进行过滤")
public HttpResult<List<String>> formatEventIds(@RequestBody SpThroughParam spThroughParam) {
String methodDescribe = getMethodDescribe("formatEventIds");
return HttpResultUtil.assembleCommonResponseResult(CommonResponseEnum.SUCCESS, spThroughService.formatEventIds(spThroughParam), methodDescribe);
}
}

View File

@@ -1,13 +0,0 @@
package com.njcn.prepare.harmonic.mapper.mysql.event;
import com.github.jeffreyning.mybatisplus.base.MppBaseMapper;
import com.njcn.prepare.harmonic.pojo.po.RActivePowerRangePO;
/**
* 有功功率趋势 Mapper 接口
* @author guofeihu
* @since 2024-08-20
*/
public interface RActivePowerRangeMapper extends MppBaseMapper<RActivePowerRangePO> {
}

View File

@@ -1,13 +0,0 @@
package com.njcn.prepare.harmonic.mapper.mysql.event;
import com.github.jeffreyning.mybatisplus.base.MppBaseMapper;
import com.njcn.prepare.harmonic.pojo.po.SpThroughPO;
/**
* 高低电压穿越 Mapper 接口
* @author guofeihu
* @since 2024-08-22
*/
public interface SpThroughMapper extends MppBaseMapper<SpThroughPO> {
}

View File

@@ -1,42 +0,0 @@
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="com.njcn.prepare.harmonic.mapper.mysql.event.RActivePowerRangeMapper">
<resultMap id="BaseResultMap" type="com.njcn.prepare.harmonic.pojo.po.RActivePowerRangePO">
<id column="id" jdbcType="VARCHAR" property="id" />
<result column="line_id" jdbcType="VARCHAR" property="lineId" />
<result column="time_id" jdbcType="DATE" property="timeId"/>
<result column="mins_time0" jdbcType="VARCHAR" property="minsTime0" />
<result column="mins_num0" jdbcType="INTEGER" property="minsNum0" />
<result column="is_or_not0" jdbcType="INTEGER" property="isOrNot0" />
<result column="mins_time1" jdbcType="VARCHAR" property="minsTime1" />
<result column="mins_num1" jdbcType="INTEGER" property="minsNum1" />
<result column="is_or_not1" jdbcType="INTEGER" property="isOrNot1" />
<result column="mins_time2" jdbcType="VARCHAR" property="minsTime2" />
<result column="mins_num2" jdbcType="INTEGER" property="minsNum2" />
<result column="is_or_not2" jdbcType="INTEGER" property="isOrNot2" />
<result column="mins_time3" jdbcType="VARCHAR" property="minsTime3" />
<result column="mins_num3" jdbcType="INTEGER" property="minsNum3" />
<result column="is_or_not3" jdbcType="INTEGER" property="isOrNot3" />
<result column="mins_time4" jdbcType="VARCHAR" property="minsTime4" />
<result column="mins_num4" jdbcType="INTEGER" property="minsNum4" />
<result column="is_or_not4" jdbcType="INTEGER" property="isOrNot4" />
<result column="mins_time5" jdbcType="VARCHAR" property="minsTime5" />
<result column="mins_num5" jdbcType="INTEGER" property="minsNum5" />
<result column="is_or_not5" jdbcType="INTEGER" property="isOrNot5" />
<result column="mins_time6" jdbcType="VARCHAR" property="minsTime6" />
<result column="mins_num6" jdbcType="INTEGER" property="minsNum6" />
<result column="is_or_not6" jdbcType="INTEGER" property="isOrNot6" />
<result column="mins_time7" jdbcType="VARCHAR" property="minsTime7" />
<result column="mins_num7" jdbcType="INTEGER" property="minsNum7" />
<result column="is_or_not7" jdbcType="INTEGER" property="isOrNot7" />
<result column="mins_time8" jdbcType="VARCHAR" property="minsTime8" />
<result column="mins_num8" jdbcType="INTEGER" property="minsNum8" />
<result column="is_or_not8" jdbcType="INTEGER" property="isOrNot8" />
<result column="mins_time9" jdbcType="VARCHAR" property="minsTime9" />
<result column="mins_num9" jdbcType="INTEGER" property="minsNum9" />
<result column="is_or_not9" jdbcType="INTEGER" property="isOrNot9" />
<result column="state" jdbcType="INTEGER" property="state" />
</resultMap>
</mapper>

View File

@@ -1,5 +0,0 @@
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="com.njcn.prepare.harmonic.mapper.mysql.event.SpThroughMapper">
</mapper>

View File

@@ -1,701 +0,0 @@
package com.njcn.prepare.harmonic.service.mysql.Impl.event;
import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.util.IdUtil;
import com.alibaba.excel.util.DateUtils;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.github.jeffreyning.mybatisplus.service.MppServiceImpl;
import com.njcn.device.biz.commApi.CommLineClient;
import com.njcn.device.biz.pojo.dto.LineDTO;
import com.njcn.device.biz.pojo.po.Overlimit;
import com.njcn.device.pq.api.OverLimitClient;
import com.njcn.event.pojo.constant.Param;
import com.njcn.harmonic.pojo.vo.PowerStatisticsTargetVO;
import com.njcn.harmonic.pojo.vo.ThdDataVO;
import com.njcn.influx.pojo.bo.CommonQueryParam;
import com.njcn.influx.pojo.constant.InfluxDBTableConstant;
import com.njcn.influx.pojo.dto.StatisticalDataDTO;
import com.njcn.influx.service.*;
import com.njcn.prepare.harmonic.mapper.mysql.event.RActivePowerRangeMapper;
import com.njcn.prepare.harmonic.pojo.param.RActivePowerRangeParam;
import com.njcn.prepare.harmonic.pojo.po.RActivePowerRangePO;
import com.njcn.prepare.harmonic.service.mysql.event.RActivePowerRangeService;
import com.njcn.supervision.api.UserLedgerFeignClient;
import com.njcn.supervision.pojo.vo.user.NewUserReportVO;
import com.njcn.system.api.DictTreeFeignClient;
import com.njcn.system.enums.DicTreeEnum;
import com.njcn.system.pojo.vo.DictTreeVO;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import java.lang.reflect.Field;
import java.text.DecimalFormat;
import java.text.SimpleDateFormat;
import java.time.Instant;
import java.time.LocalDate;
import java.time.ZoneId;
import java.time.format.DateTimeFormatter;
import java.util.*;
import java.util.concurrent.atomic.AtomicBoolean;
import java.util.stream.Collectors;
/**
* 有功功率趋势 服务实现类
*
* @author guofeihu
* @since 2024-08-22
*/
@Slf4j
@Service
@RequiredArgsConstructor
public class RActivePowerRangeServiceImpl extends MppServiceImpl<RActivePowerRangeMapper, RActivePowerRangePO> implements RActivePowerRangeService {
private final CommonService commonService;
private final IDataVService iDataVService;
private final IDataIService iDataIService;
private final DataPltService dataPltService;
private final DataInHarmVService dataInHarmVService;
private final DataHarmRateVService dataHarmRateVService;
private final DataFlucService dataFlucService;
private final CommLineClient commLineClient;
private final DictTreeFeignClient dictTreeFeignClient;
private final OverLimitClient overLimitClient;
private final UserLedgerFeignClient userLedgerFeignClient;
private DateTimeFormatter formatter = DateTimeFormatter.ofPattern(Param.DATE_FORMAT);
private final DecimalFormat df = new DecimalFormat(com.njcn.harmonic.constant.Param.DECIMAL_FORMATSTR);
private SimpleDateFormat sdf = new SimpleDateFormat(Param.DATE_FORMAT);
private List<String> PHASE = Arrays.asList(InfluxDBTableConstant.PHASE_TYPE_A, InfluxDBTableConstant.PHASE_TYPE_B, InfluxDBTableConstant.PHASE_TYPE_C);
/**
* 整个算法的业务逻辑:
* 1:查询InfluxDb的功率表:data_harmpower_p
* 2:遍历功率集合将功率(p字段) / line_id监测点绑定的新能源场站中的风电场的额定功率,看落在哪个区间内
* 3:遍历功率集合将每条功率对应的各个指标(指标的所有相别和统计方式都要一一比较)与国标限值比较看看是否越限(功率对应的各个指标详情请见下方)
* --------------------------------指标---------------------------------
* 电压偏差 data_v vu_dev 电压偏差 如果vu_dev>0,使用上偏差限值对比如果vu_dev<0,使用下偏差限值对比
* 谐波电压 data_v v_thd 电压总谐波总谐波畸变率 有一个指标超标,则谐波电压超标
* data_harmrate_v v2-v25 2-25次谐波电压含有率
* 谐波电流 data_i i2-i25 2-25次谐波电流幅值 有一个指标超标,则谐波电压超标
* 三相电压不平衡度 data_v v_unbalance
* 电压波动 data_fluc fluc
* 长时闪变 data_plt plt
* 间谐波电压含有率 data_inharm_v v1-v16 0.5-15.5次间谐波电压含有率 有一个指标超标,则谐波电压超标
* 电流不平衡度 data_i i_unbalance 这个不确定,找宝哥确认下
*
* @param rActivePowerRangeParam
* @return
*/
@Override
@Transactional(rollbackFor = Exception.class)
public List<PowerStatisticsTargetVO> record(RActivePowerRangeParam rActivePowerRangeParam) {
DictTreeVO windFarms = dictTreeFeignClient.queryByCode(DicTreeEnum.Wind_Farms.getCode()).getData();
if (rActivePowerRangeParam == null) {
rActivePowerRangeParam = new RActivePowerRangeParam();
}
//返回的最终结果
List<PowerStatisticsTargetVO> powerStatisticsTargetVOS = new ArrayList<>();
//默认初始化开始和结束时间
String startTime = getTime(rActivePowerRangeParam.getInterval(), 0);
String endTime = getTime(rActivePowerRangeParam.getInterval(), 1);
//获取时间段内的有功功率集合
List<CommonQueryParam> commonQueryParams = new ArrayList<>();
CommonQueryParam commonQueryParam = new CommonQueryParam();
//控制参数中如果search为true,则获取有功功率集合的时间段内为BaseParam中的searchBeginTime和searchEndTime(用于前端有功功率查询页面相关接口)
if (rActivePowerRangeParam.isSearch()) {
if (rActivePowerRangeParam.isSearchTimeFort()) {
startTime = rActivePowerRangeParam.getSearchBeginTime() + Param.BEGIN;
endTime = rActivePowerRangeParam.getSearchEndTime() + Param.END;
} else {
startTime = rActivePowerRangeParam.getSearchBeginTime();
endTime = rActivePowerRangeParam.getSearchEndTime();
}
commonQueryParam.setLineId(rActivePowerRangeParam.getLineId());
}
//时间段
commonQueryParam.setStartTime(startTime);
commonQueryParam.setEndTime(endTime);
//功率表data_harmpower_p及字段p
commonQueryParam.setTableName(InfluxDBTableConstant.DATA_HARM_POWER_P);
commonQueryParam.setColumnName("p");
commonQueryParams.add(commonQueryParam);
//查询功率表(多个统计方式及相别)
List<StatisticalDataDTO> dataHarmPowerPS = commonService.getNewDeviceRtDataByTime(commonQueryParams);
//由于前端写死了各个指标的相别(只有A、B、C所以这边直接限制死了)
dataHarmPowerPS = dataHarmPowerPS.stream().filter(param -> PHASE.contains(param.getPhaseType())).collect(Collectors.toList());
//有功功率趋势表是按照监测点来划分的 所以这边需要根据监测点来分组
Map<String, List<StatisticalDataDTO>> lineMap = dataHarmPowerPS.stream().collect(Collectors.groupingBy(StatisticalDataDTO::getLineId));
RActivePowerRangeParam finalRActivePowerRangeParam = rActivePowerRangeParam;
//以下这段逻辑较耗时(主要是for循环),主要是要遍历所有的有功功率,在根据有功功率查询各个指标进行比较(最耗时的是有功功率查询各个指标,所以一但有功功率很多则遍历较慢)
log.info("当前遍历的功率根据监测点分组后长度为:{},集合总长为:{},现在开始遍历,{}", lineMap.size(), dataHarmPowerPS.size(), sdf.format(new Date()));
lineMap.forEach((lineId, lineGroupList) -> {
log.info("当前遍历的监测点ID为:{},监测点集合长为:{},现在开始遍历,{}", lineId, lineGroupList.size(), sdf.format(new Date()));
//获取监测点的国标限值
List<Overlimit> overlimits = overLimitClient.getOverLimitByLineIds(Arrays.asList(lineId)).getData();
//该监测点必须要有国标限值
if (overlimits != null && !overlimits.isEmpty()) {
Overlimit overlimit = overlimits.get(0);
//获取监测点
LineDTO lineDTO = commLineClient.getLineDetail(lineId).getData();
//监测点必须绑定新能源站
if (lineDTO != null && lineDTO.getObjId() != null && windFarms.getId().equals(lineDTO.getBigObjType())) {
List<NewUserReportVO> data = userLedgerFeignClient.getUserReportByIds(Collections.singletonList(lineDTO.getObjId())).getData();
if (CollUtil.isNotEmpty(data)) {
//新能源站有些必须是风电场
RActivePowerRangePO rActivePowerRangePO = new RActivePowerRangePO();
rActivePowerRangePO.setLineId(lineId);
rActivePowerRangePO.setTimeId(LocalDate.now());
rActivePowerRangePO.setId(IdUtil.simpleUUID());
LambdaQueryWrapper<RActivePowerRangePO> lambdaQueryWrapper = new LambdaQueryWrapper<>();
lambdaQueryWrapper.eq(RActivePowerRangePO::getLineId, lineId).eq(RActivePowerRangePO::getTimeId, LocalDate.now());
//控制参数-强制刷新
if (finalRActivePowerRangeParam.isRefresh()) {
this.baseMapper.delete(lambdaQueryWrapper);
}
//控制参数-是否查询及查询新增(主要用于harmonic-boot-getDataByLineId方法,避免每次执行都会执行循环,也即当日执行完一次即可)
if (!this.baseMapper.selectList(lambdaQueryWrapper).isEmpty() && (finalRActivePowerRangeParam.isSearch() && finalRActivePowerRangeParam.isSearchForAdd())) {
return;
}
//当前监测点的功率数据在根据时间分组然后取出一个时间分组内最大的值
Map<Instant, List<StatisticalDataDTO>> timeMap = lineGroupList.stream().collect(Collectors.groupingBy(StatisticalDataDTO::getTime));
timeMap.forEach((time, timeGroupList) -> {
//取出当前时间分组内最大的一个值来判断是否越界
Optional<StatisticalDataDTO> optional = timeGroupList.stream().max(Comparator.comparingDouble(StatisticalDataDTO::getValue));
StatisticalDataDTO statisticalDataDTO = optional.get();
PowerStatisticsTargetVO powerStatisticsTargetVO = new PowerStatisticsTargetVO();
//设置时间为当前功率的时间
powerStatisticsTargetVO.setTime(statisticalDataDTO.getTime().atZone(ZoneId.systemDefault()).format(formatter));
//当前功率的p字段 / 风电场额定功率
double temp = statisticalDataDTO.getValue() / data.get(0).getRatePower();
//区间过滤下(如果进去此判断 那么只能是查询某个区间下的指标越限列表)
if (finalRActivePowerRangeParam.isSearch() && finalRActivePowerRangeParam.getField() != null) {
if (Double.parseDouble(finalRActivePowerRangeParam.getField()) < temp * 10 && temp * 10 <= Double.parseDouble(finalRActivePowerRangeParam.getField()) + 1) {
//判断当前区间每个指标是否越限(根据type来区分设置到哪个区间对应的是否越限字段)
installLimit(rActivePowerRangePO, statisticalDataDTO, overlimit, Integer.parseInt(finalRActivePowerRangeParam.getField()), powerStatisticsTargetVO);
powerStatisticsTargetVOS.add(powerStatisticsTargetVO);
}
} else {
//否则是正常的定时任务插入,或者前端搜索插入
//设置每个区间的统计时间
rActivePowerRangePO.setMinsTime0(commonQueryParam.getStartTime() + "," + commonQueryParam.getEndTime());
rActivePowerRangePO.setMinsTime1(commonQueryParam.getStartTime() + "," + commonQueryParam.getEndTime());
rActivePowerRangePO.setMinsTime2(commonQueryParam.getStartTime() + "," + commonQueryParam.getEndTime());
rActivePowerRangePO.setMinsTime3(commonQueryParam.getStartTime() + "," + commonQueryParam.getEndTime());
rActivePowerRangePO.setMinsTime4(commonQueryParam.getStartTime() + "," + commonQueryParam.getEndTime());
rActivePowerRangePO.setMinsTime5(commonQueryParam.getStartTime() + "," + commonQueryParam.getEndTime());
rActivePowerRangePO.setMinsTime6(commonQueryParam.getStartTime() + "," + commonQueryParam.getEndTime());
rActivePowerRangePO.setMinsTime7(commonQueryParam.getStartTime() + "," + commonQueryParam.getEndTime());
rActivePowerRangePO.setMinsTime8(commonQueryParam.getStartTime() + "," + commonQueryParam.getEndTime());
rActivePowerRangePO.setMinsTime9(commonQueryParam.getStartTime() + "," + commonQueryParam.getEndTime());
if (temp <= 0.1) {
//占有率区间个数+1
rActivePowerRangePO.setMinsNum0(rActivePowerRangePO.getMinsNum0() + 1);
//判断当前区间每个指标是否越限
installLimit(rActivePowerRangePO, statisticalDataDTO, overlimit, 0, powerStatisticsTargetVO);
} else if (0.1 < temp && temp <= 0.2) {
rActivePowerRangePO.setMinsNum1(rActivePowerRangePO.getMinsNum1() + 1);
installLimit(rActivePowerRangePO, statisticalDataDTO, overlimit, 1, powerStatisticsTargetVO);
} else if (0.2 < temp && temp <= 0.3) {
rActivePowerRangePO.setMinsNum2(rActivePowerRangePO.getMinsNum2() + 1);
installLimit(rActivePowerRangePO, statisticalDataDTO, overlimit, 2, powerStatisticsTargetVO);
} else if (0.3 < temp && temp <= 0.4) {
rActivePowerRangePO.setMinsNum3(rActivePowerRangePO.getMinsNum3() + 1);
installLimit(rActivePowerRangePO, statisticalDataDTO, overlimit, 3, powerStatisticsTargetVO);
} else if (0.4 < temp && temp <= 0.5) {
rActivePowerRangePO.setMinsNum4(rActivePowerRangePO.getMinsNum4() + 1);
installLimit(rActivePowerRangePO, statisticalDataDTO, overlimit, 4, powerStatisticsTargetVO);
} else if (0.5 < temp && temp <= 0.6) {
rActivePowerRangePO.setMinsNum5(rActivePowerRangePO.getMinsNum5() + 1);
installLimit(rActivePowerRangePO, statisticalDataDTO, overlimit, 5, powerStatisticsTargetVO);
} else if (0.6 < temp && temp <= 0.7) {
rActivePowerRangePO.setMinsNum6(rActivePowerRangePO.getMinsNum6() + 1);
installLimit(rActivePowerRangePO, statisticalDataDTO, overlimit, 6, powerStatisticsTargetVO);
} else if (0.7 < temp && temp <= 0.8) {
rActivePowerRangePO.setMinsNum7(rActivePowerRangePO.getMinsNum7() + 1);
installLimit(rActivePowerRangePO, statisticalDataDTO, overlimit, 7, powerStatisticsTargetVO);
} else if (0.8 < temp && temp <= 0.9) {
rActivePowerRangePO.setMinsNum8(rActivePowerRangePO.getMinsNum8() + 1);
installLimit(rActivePowerRangePO, statisticalDataDTO, overlimit, 8, powerStatisticsTargetVO);
} else if (temp > 0.9) {
rActivePowerRangePO.setMinsNum9(rActivePowerRangePO.getMinsNum9() + 1);
installLimit(rActivePowerRangePO, statisticalDataDTO, overlimit, 9, powerStatisticsTargetVO);
}
powerStatisticsTargetVOS.add(powerStatisticsTargetVO);
}
});
//根据日期及lineId当天不能重复执行
if (this.baseMapper.selectList(lambdaQueryWrapper).isEmpty() && (finalRActivePowerRangeParam.isSearch() && finalRActivePowerRangeParam.isSearchForAdd() || !finalRActivePowerRangeParam.isSearch())) {
this.baseMapper.insert(rActivePowerRangePO);
}
}
}
}
});
log.info("当前遍历的功率根据监测点分组后长度为:{},集合总长为:{},遍历结束,{}", lineMap.size(), dataHarmPowerPS.size(), sdf.format(new Date()));
if (rActivePowerRangeParam.isSearch()) {
return powerStatisticsTargetVOS;
}
return null;
}
private void installLimit(RActivePowerRangePO rActivePowerRangePO, StatisticalDataDTO statisticalDataDTO, Overlimit overlimit, int type, PowerStatisticsTargetVO powerStatisticsTargetVO) {
//根据当前最大值的功率查询各个指标信息
//电压偏差
List<StatisticalDataDTO> vu_dev = commonQuery(InfluxDBTableConstant.DATA_V, "vuDev", statisticalDataDTO, null, null);
//谐波电压
List<StatisticalDataDTO> v_thd = commonQuery(InfluxDBTableConstant.DATA_V, "vThd", statisticalDataDTO, null, null);
List<StatisticalDataDTO> v = commonQuery(InfluxDBTableConstant.DATA_HARM_RATE_V, "v", statisticalDataDTO, 2, 25);
//谐波电流
List<StatisticalDataDTO> i = commonQuery(InfluxDBTableConstant.DATA_I, "i", statisticalDataDTO, 2, 25);
//三相电压不平衡度
List<StatisticalDataDTO> v_unbalance = commonQuery(InfluxDBTableConstant.DATA_V, "vUnbalance", statisticalDataDTO, null, null);
//电压波动
List<StatisticalDataDTO> fluc = commonQuery(InfluxDBTableConstant.DATA_FLUC, "fluc", statisticalDataDTO, null, null);
//长时闪变
List<StatisticalDataDTO> plt = commonQuery(InfluxDBTableConstant.DATA_PLT, "plt", statisticalDataDTO, null, null);
//间谐波电压含有率
List<StatisticalDataDTO> v1 = commonQuery(InfluxDBTableConstant.DATA_IN_HARM_V, "v", statisticalDataDTO, 1, 16);
//电流不平衡度
List<StatisticalDataDTO> i_unbalance = commonQuery(InfluxDBTableConstant.DATA_I, "iUnbalance", statisticalDataDTO, null, null);
//此标识用来记录当前区间下指标是否越限
boolean isLimit = false;
//电压偏差是否越限比较(此指标比较较为特殊所以单独一个重载的判断方法)
Float isVoltageOffsetLimit = isLimit(vu_dev, overlimit);
//电压偏差指标详细数据
powerStatisticsTargetVO.setVoltageOffsetList(toThdDataVO(vu_dev, Param.voltageOffset, null, isVoltageOffsetLimit));
if (isVoltageOffsetLimit != null) {
isLimit = true;
//电压偏差越限
powerStatisticsTargetVO.setVoltageOffset(1);
}
//谐波电压比较较为特殊需要比较两个点
//谐波电压指标详细数据
powerStatisticsTargetVO.setVTimesList(toThdDataVO(v, Param.vTimes, overlimit, null));
//谐波电压是否越限比较(不过指标详细数据还是取data_harmrate_v表里的数据)
if (isLimit(v, Param.vTimes, InfluxDBTableConstant.CP95, overlimit, null)) {
isLimit = true;
//谐波电流越限
powerStatisticsTargetVO.setVTimes(1);
}
if (isLimit(v_thd, Param.vTimes, InfluxDBTableConstant.CP95, null, overlimit.getUaberrance())) {
isLimit = true;
//谐波电流越限
powerStatisticsTargetVO.setVTimes(1);
}
//谐波电流指标详细数据
powerStatisticsTargetVO.setITimestList(toThdDataVO(i, Param.iTimes, overlimit, null));
//谐波电流是否越限比较
if (isLimit(i, Param.vTimes, InfluxDBTableConstant.CP95, overlimit, null)) {
isLimit = true;
//谐波电流越限
powerStatisticsTargetVO.setITimes(1);
}
//三相电压不平衡度指标详细数据
powerStatisticsTargetVO.setUbalanceList(toThdDataVO(v_unbalance, Param.ubalance, null, overlimit.getUbalance()));
//三相电压不平衡度是否越限比较
if (isLimit(v_unbalance, Param.ubalance, InfluxDBTableConstant.CP95, null, overlimit.getUbalance())) {
isLimit = true;
//三相电压不平衡度越限
powerStatisticsTargetVO.setUbalance(1);
}
//电压波动指标详细数据
powerStatisticsTargetVO.setVoltageFluctuationList(toThdDataVO(fluc, Param.voltageFluctuation, null, overlimit.getVoltageFluctuation()));
//电压波动是否越限比较
if (isLimit(fluc, Param.voltageFluctuation, InfluxDBTableConstant.MAX, null, overlimit.getVoltageFluctuation())) {
isLimit = true;
//电压波动变越限
powerStatisticsTargetVO.setVoltageFluctuation(1);
}
//长时闪变指标详细数据
powerStatisticsTargetVO.setFlickerList(toThdDataVO(plt, Param.flicker, null, overlimit.getFlicker()));
//长时闪变是否越限比较
if (isLimit(plt, Param.flicker, InfluxDBTableConstant.MAX, null, overlimit.getFlicker())) {
isLimit = true;
//长时闪变越限
powerStatisticsTargetVO.setFlicker(1);
}
//间谐波电压含有率指标详细数据
powerStatisticsTargetVO.setInterHarmonicList(toThdDataVO(v1, Param.interHarmonic, overlimit, null));
//间谐波电压含有率是否越限比较
if (isLimit(v1, Param.interHarmonic, InfluxDBTableConstant.CP95, overlimit, null)) {
isLimit = true;
//间谐波电压含有率越限
powerStatisticsTargetVO.setInterHarmonic(1);
}
//电流不平衡度指标详细数据
powerStatisticsTargetVO.setSequenceCurrentUnbalanceList(toThdDataVO(i_unbalance, Param.sequenceCurrentUnbalance, null, overlimit.getINeg()));
//电流不平衡度是否越限比较
if (isLimit(i_unbalance, Param.sequenceCurrentUnbalance, null, null, overlimit.getINeg())) {
isLimit = true;
//电流不平衡度越限
powerStatisticsTargetVO.setSequenceCurrentUnbalance(1);
}
//区间是否越限标识
if (isLimit) {
switch (type) {
case 0:
rActivePowerRangePO.setIsOrNot0(1);
break;
case 1:
rActivePowerRangePO.setIsOrNot1(1);
break;
case 2:
rActivePowerRangePO.setIsOrNot2(1);
break;
case 3:
rActivePowerRangePO.setIsOrNot3(1);
break;
case 4:
rActivePowerRangePO.setIsOrNot4(1);
break;
case 5:
rActivePowerRangePO.setIsOrNot5(1);
break;
case 6:
rActivePowerRangePO.setIsOrNot6(1);
break;
case 7:
rActivePowerRangePO.setIsOrNot7(1);
break;
case 8:
rActivePowerRangePO.setIsOrNot8(1);
break;
case 9:
rActivePowerRangePO.setIsOrNot9(1);
break;
}
}
}
private Float isLimit(List<StatisticalDataDTO> list, Overlimit overlimit) {
List<StatisticalDataDTO> maxList = list.stream().filter(dto -> dto.equals(InfluxDBTableConstant.MAX)).collect(Collectors.toList());
List<StatisticalDataDTO> minList = list.stream().filter(dto -> dto.equals(InfluxDBTableConstant.MIN)).collect(Collectors.toList());
StatisticalDataDTO maxDto = maxList.stream().max(Comparator.comparingDouble(StatisticalDataDTO::getValue)).orElse(null);
StatisticalDataDTO minDto = minList.stream().min(Comparator.comparingDouble(StatisticalDataDTO::getValue)).orElse(null);
if (!maxList.isEmpty()) {
if (Double.compare(maxDto.getValue(), 0) > 0 && Double.compare(maxDto.getValue(), overlimit.getVoltageDev()) < 0) {
return overlimit.getVoltageDev();
}
}
if (!minList.isEmpty()) {
if (Double.compare(minDto.getValue(), 0) < 0 && Double.compare(minDto.getValue(), overlimit.getUvoltageDev()) > 0) {
return overlimit.getUvoltageDev();
}
}
return null;
}
private boolean isLimit(List<StatisticalDataDTO> list, String name, String valueType, Overlimit overlimit, Float limit) {
AtomicBoolean ist = new AtomicBoolean(false);
if (valueType != null) {
list = list.stream().filter(dto -> dto.getValueType().equals(valueType)).collect(Collectors.toList());
}
if (overlimit != null) {
String field = "";
switch (name) {
case Param.vTimes:
field = "uharm";
break;
case Param.iTimes:
field = "iharm";
break;
case Param.interHarmonic:
field = "inuharm";
break;
}
Map<String, List<StatisticalDataDTO>> frequencyMap = list.stream().collect(Collectors.groupingBy(StatisticalDataDTO::getFrequency));
String finalField = field;
frequencyMap.forEach((frequency, frequencyGroupList) -> {
StatisticalDataDTO statisticalDataDTO = frequencyGroupList.stream().max(Comparator.comparingDouble(StatisticalDataDTO::getValue)).orElse(null);
Float value = (Float) reflexObjValue(overlimit, finalField + Integer.parseInt(frequency));
if (value != null) {
if (statisticalDataDTO.getValue() != null && Double.compare(statisticalDataDTO.getValue(), value) > 0) {
ist.set(true);
return;
}
}
});
} else {
StatisticalDataDTO statisticalDataDTO = list.stream().max(Comparator.comparingDouble(StatisticalDataDTO::getValue)).orElse(null);
if (statisticalDataDTO != null && statisticalDataDTO.getValue() != null && Double.compare(statisticalDataDTO.getValue(), limit) > 0) {
return true;
}
}
return ist.get();
}
//根据各个指标数组信息组装成前端需要的格式
private List<ThdDataVO> toThdDataVO(List<StatisticalDataDTO> list, String name, Overlimit overlimit, Float limit) {
List<ThdDataVO> thdDataVOS = new ArrayList<>();
//带有谐波次数的指标
if (overlimit != null) {
String field = "";
double c = 0;
switch (name) {
//谐波电压和电流默认谐波次数2-25
case Param.vTimes:
field = "uharm";
break;
case Param.iTimes:
field = "iharm";
break;
//间谐波电压含有率默认谐波次数1-16
case Param.interHarmonic:
field = "inuharm";
c = 0.5;
break;
}
//根据谐波次数分组,分组完则frequencyMap数据维度:当前谐波次数下的各个统计方式和相别他们的值是多少
Map<String, List<StatisticalDataDTO>> frequencyMap = list.stream().collect(Collectors.groupingBy(StatisticalDataDTO::getFrequency));
double finalC = c;
String finalField = field;
frequencyMap.forEach((frequency, frequencyGroupList) -> {
Integer frequencyNum = Integer.parseInt(frequency);
//反射获取当前谐波次数对应的国标限值
Float frequencyLimit = (Float) reflexObjValue(overlimit, finalField + frequencyNum);
//相别和统计方式的值和ThdDataVO字段相对于
ThdDataVO tdv = initThdDataVO(frequencyGroupList, frequencyLimit);
if (tdv != null) {
tdv.setAnotherName(name + (((frequencyNum - finalC) + "").replace(".0", "")) + "");
tdv.setLimit((Float) reflexObjValue(overlimit, finalField + frequencyNum));
tdv.setFrequency(frequencyNum);
thdDataVOS.add(tdv);
}
});
} else {
//无谐波次数
ThdDataVO tdv = initThdDataVO(list, limit);
if (tdv != null) {
tdv.setAnotherName(name);
tdv.setLimit(limit);
thdDataVOS.add(tdv);
}
}
return thdDataVOS.stream().sorted(Comparator.comparing(ThdDataVO::getFrequency)).collect(Collectors.toList());
}
private ThdDataVO initThdDataVO(List<StatisticalDataDTO> list, Float limit) {
ThdDataVO tdv = new ThdDataVO();
boolean isF = false;
//list包含了一组不同相别不同统计方式的数据(最多12条,因为统计方式和相别自由组合最多12条)
for (StatisticalDataDTO statisticalDataDTO : list) {
String valueType = statisticalDataDTO.getValueType();
String phasicType = statisticalDataDTO.getPhaseType();
String value = null;
if (statisticalDataDTO.getValue() != null) {
value = df.format(statisticalDataDTO.getValue());
//判断是否有指标越界(不管哪一个相别及统计方式的指标,)
if (Double.compare(statisticalDataDTO.getValue(), limit) > 0) {
isF = true;
}
}
//统计方式和相别渲染ThdDataVO
switch (valueType) {
case InfluxDBTableConstant.AVG:
switch (phasicType) {
case InfluxDBTableConstant.PHASE_TYPE_A:
tdv.setAVGPhaseA(value);
break;
case InfluxDBTableConstant.PHASE_TYPE_B:
tdv.setAVGPhaseB(value);
break;
case InfluxDBTableConstant.PHASE_TYPE_C:
tdv.setAVGPhaseC(value);
break;
}
break;
case InfluxDBTableConstant.CP95:
switch (phasicType) {
case InfluxDBTableConstant.PHASE_TYPE_A:
tdv.setCP95PhaseA(value);
break;
case InfluxDBTableConstant.PHASE_TYPE_B:
tdv.setCP95PhaseB(value);
break;
case InfluxDBTableConstant.PHASE_TYPE_C:
tdv.setCP95PhaseC(value);
break;
}
break;
case InfluxDBTableConstant.MIN:
switch (phasicType) {
case InfluxDBTableConstant.PHASE_TYPE_A:
tdv.setMINPhaseA(value);
break;
case InfluxDBTableConstant.PHASE_TYPE_B:
tdv.setMINPhaseB(value);
break;
case InfluxDBTableConstant.PHASE_TYPE_C:
tdv.setMINPhaseC(value);
break;
}
break;
case InfluxDBTableConstant.MAX:
switch (phasicType) {
case InfluxDBTableConstant.PHASE_TYPE_A:
tdv.setMAXPhaseA(value);
break;
case InfluxDBTableConstant.PHASE_TYPE_B:
tdv.setMAXPhaseB(value);
break;
case InfluxDBTableConstant.PHASE_TYPE_C:
tdv.setMAXPhaseC(value);
break;
}
break;
}
}
//如果所有的相别和统计方式都没有值则可直接忽略该条数据或者没有一个相别及统计方式的指标越界也可以忽略
if (tdv.getAVGPhaseA() != null || tdv.getAVGPhaseB() != null
|| tdv.getAVGPhaseC() != null || tdv.getCP95PhaseA() != null
|| tdv.getCP95PhaseB() != null || tdv.getCP95PhaseC() != null
|| tdv.getMINPhaseA() != null || tdv.getMINPhaseB() != null
|| tdv.getMINPhaseC() != null || tdv.getMAXPhaseA() != null
|| tdv.getMAXPhaseB() != null || tdv.getMAXPhaseC() != null) {
if (isF) {
return tdv;
}
}
return null;
}
//组装公共查询(有谐波次数指标查询和没有谐波次数指标查询)
private List<StatisticalDataDTO> commonQuery(String tableName, String columnName, StatisticalDataDTO statisticalDataDTO, Integer start, Integer end) {
String time = statisticalDataDTO.getTime().atZone(ZoneId.systemDefault()).format(formatter);
List<Object> data = null;
switch (tableName) {
case InfluxDBTableConstant.DATA_V:
data = Collections.singletonList(iDataVService.getNewDataV(statisticalDataDTO.getLineId(), time, time));
break;
case InfluxDBTableConstant.DATA_HARM_RATE_V:
data = Collections.singletonList(dataHarmRateVService.getNewDataHarmRateV(statisticalDataDTO.getLineId(), time, time));
break;
case InfluxDBTableConstant.DATA_I:
data = Collections.singletonList(iDataIService.getNewDataI(statisticalDataDTO.getLineId(), time, time));
break;
case InfluxDBTableConstant.DATA_FLUC:
data = Collections.singletonList(dataFlucService.getNewDataFluc(statisticalDataDTO.getLineId(), time, time));
break;
case InfluxDBTableConstant.DATA_PLT:
data = Collections.singletonList(dataPltService.getNewDataPlt(statisticalDataDTO.getLineId(), time, time));
break;
case InfluxDBTableConstant.DATA_IN_HARM_V:
data = Collections.singletonList(dataInHarmVService.getNewDataInHarmV(statisticalDataDTO.getLineId(), time, time));
break;
}
List<StatisticalDataDTO> list = new ArrayList<>();
if (!data.isEmpty()) {
data = (List<Object>) data.get(0);
for (Object item : data) {
String phaseType = (reflexObjValue(item, "phaseType").toString());
if (PHASE.contains(phaseType)) {
if (start != null) {
for (int i = start; i <= end; i++) {
StatisticalDataDTO dto = new StatisticalDataDTO();
dto.setPhaseType(phaseType);
dto.setValueType((reflexObjValue(item, "valueType").toString()));
dto.setTime((Instant) reflexObjValue(item, "time"));
dto.setLineId(reflexObjValue(item, "lineId").toString());
dto.setValue((Double) reflexObjValue(item, columnName + i));
dto.setFrequency(i + "");
list.add(dto);
}
} else {
StatisticalDataDTO dto = new StatisticalDataDTO();
dto.setPhaseType(phaseType);
dto.setValueType((reflexObjValue(item, "valueType").toString()));
dto.setTime((Instant) reflexObjValue(item, "time"));
dto.setLineId(reflexObjValue(item, "lineId").toString());
dto.setValue((Double) reflexObjValue(item, columnName));
list.add(dto);
}
}
}
}
return list;
}
//反射获取值
private Object reflexObjValue(Object obj, String fieldName) {
try {
Class clazz = obj.getClass();
Field field = clazz.getDeclaredField(fieldName);
field.setAccessible(true);
return field.get(obj);
} catch (Exception e) {
e.printStackTrace();
}
return null;
}
//根据时间间隔获取间隔前时间或获取昨晚最晚时间
private String getTime(long interval, int type) {
DateTimeFormatter sdf = DateTimeFormatter.ofPattern(DateUtils.DATE_FORMAT_10);
LocalDate yesterday;
if (type == 0) {
yesterday = LocalDate.now().minusDays(interval);
return yesterday.format(sdf) + Param.BEGIN;
} else {
yesterday = LocalDate.now().minusDays(1);
return yesterday.format(sdf) + Param.END;
}
}
@Override
public RActivePowerRangePO getDataByLineId(String lineId, String startTime, String endTime) {
LambdaQueryWrapper<RActivePowerRangePO> lambdaQueryWrapper = new LambdaQueryWrapper();
lambdaQueryWrapper.eq(RActivePowerRangePO::getLineId, lineId).eq(RActivePowerRangePO::getState, "1")
.between(RActivePowerRangePO::getTimeId, startTime, endTime);
List<RActivePowerRangePO> rActivePowerRangePOS = this.baseMapper.selectList(lambdaQueryWrapper);
if (!rActivePowerRangePOS.isEmpty()) {
RActivePowerRangePO rActivePowerRangePO = new RActivePowerRangePO();
rActivePowerRangePO.setLineId(lineId);
//多条记录则次数累加,是否越限只要有一个区间越限则统一视为该区间越限
for (RActivePowerRangePO rangePO : rActivePowerRangePOS) {
rActivePowerRangePO.setMinsNum0(rangePO.getMinsNum0() + rActivePowerRangePO.getMinsNum0());
rActivePowerRangePO.setMinsNum1(rangePO.getMinsNum1() + rActivePowerRangePO.getMinsNum1());
rActivePowerRangePO.setMinsNum2(rangePO.getMinsNum2() + rActivePowerRangePO.getMinsNum2());
rActivePowerRangePO.setMinsNum3(rangePO.getMinsNum3() + rActivePowerRangePO.getMinsNum3());
rActivePowerRangePO.setMinsNum4(rangePO.getMinsNum4() + rActivePowerRangePO.getMinsNum4());
rActivePowerRangePO.setMinsNum5(rangePO.getMinsNum5() + rActivePowerRangePO.getMinsNum5());
rActivePowerRangePO.setMinsNum6(rangePO.getMinsNum6() + rActivePowerRangePO.getMinsNum6());
rActivePowerRangePO.setMinsNum7(rangePO.getMinsNum7() + rActivePowerRangePO.getMinsNum7());
rActivePowerRangePO.setMinsNum8(rangePO.getMinsNum8() + rActivePowerRangePO.getMinsNum8());
rActivePowerRangePO.setMinsNum9(rangePO.getMinsNum9() + rActivePowerRangePO.getMinsNum9());
rActivePowerRangePO.setIsOrNot0(rangePO.getIsOrNot0() + rActivePowerRangePO.getIsOrNot0());
rActivePowerRangePO.setIsOrNot1(rangePO.getIsOrNot1() + rActivePowerRangePO.getIsOrNot1());
rActivePowerRangePO.setIsOrNot2(rangePO.getIsOrNot2() + rActivePowerRangePO.getIsOrNot2());
rActivePowerRangePO.setIsOrNot3(rangePO.getIsOrNot3() + rActivePowerRangePO.getIsOrNot3());
rActivePowerRangePO.setIsOrNot4(rangePO.getIsOrNot4() + rActivePowerRangePO.getIsOrNot4());
rActivePowerRangePO.setIsOrNot5(rangePO.getIsOrNot5() + rActivePowerRangePO.getIsOrNot5());
rActivePowerRangePO.setIsOrNot6(rangePO.getIsOrNot6() + rActivePowerRangePO.getIsOrNot6());
rActivePowerRangePO.setIsOrNot7(rangePO.getIsOrNot7() + rActivePowerRangePO.getIsOrNot7());
rActivePowerRangePO.setIsOrNot8(rangePO.getIsOrNot8() + rActivePowerRangePO.getIsOrNot8());
rActivePowerRangePO.setIsOrNot9(rangePO.getIsOrNot9() + rActivePowerRangePO.getIsOrNot9());
rActivePowerRangePO.setMinsTime0(rangePO.getMinsTime0() + "&" + rActivePowerRangePO.getMinsTime0());
rActivePowerRangePO.setMinsTime1(rangePO.getMinsTime1() + "&" + rActivePowerRangePO.getMinsTime1());
rActivePowerRangePO.setMinsTime2(rangePO.getMinsTime2() + "&" + rActivePowerRangePO.getMinsTime2());
rActivePowerRangePO.setMinsTime3(rangePO.getMinsTime3() + "&" + rActivePowerRangePO.getMinsTime3());
rActivePowerRangePO.setMinsTime4(rangePO.getMinsTime4() + "&" + rActivePowerRangePO.getMinsTime4());
rActivePowerRangePO.setMinsTime5(rangePO.getMinsTime5() + "&" + rActivePowerRangePO.getMinsTime5());
rActivePowerRangePO.setMinsTime6(rangePO.getMinsTime6() + "&" + rActivePowerRangePO.getMinsTime6());
rActivePowerRangePO.setMinsTime7(rangePO.getMinsTime7() + "&" + rActivePowerRangePO.getMinsTime7());
rActivePowerRangePO.setMinsTime8(rangePO.getMinsTime8() + "&" + rActivePowerRangePO.getMinsTime8());
rActivePowerRangePO.setMinsTime9(rangePO.getMinsTime9() + "&" + rActivePowerRangePO.getMinsTime9());
}
return rActivePowerRangePO;
}
return null;
}
}

View File

@@ -1,334 +0,0 @@
package com.njcn.prepare.harmonic.service.mysql.Impl.event;
import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.date.DatePattern;
import cn.hutool.core.util.IdUtil;
import cn.hutool.core.util.ObjectUtil;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.github.jeffreyning.mybatisplus.service.MppServiceImpl;
import com.njcn.device.pms.pojo.param.MonitorTerminalParam;
import com.njcn.device.pq.api.DeptLineFeignClient;
import com.njcn.device.pq.api.LineFeignClient;
import com.njcn.device.pq.pojo.vo.LineDetailDataVO;
import com.njcn.event.api.EventDetailFeignClient;
import com.njcn.event.api.TransientFeignClient;
import com.njcn.event.file.pojo.dto.WaveDataDTO;
import com.njcn.event.pojo.param.EventCountParam;
import com.njcn.event.pojo.po.RmpEventDetailPO;
import com.njcn.prepare.harmonic.mapper.mysql.event.SpThroughMapper;
import com.njcn.prepare.harmonic.pojo.param.SpThroughParam;
import com.njcn.prepare.harmonic.pojo.po.SpThroughPO;
import com.njcn.prepare.harmonic.pojo.vo.SpThroughVO;
import com.njcn.prepare.harmonic.service.mysql.event.SpThroughService;
import com.njcn.supervision.api.UserLedgerFeignClient;
import com.njcn.supervision.pojo.vo.user.NewUserReportVO;
import com.njcn.system.api.DicDataFeignClient;
import com.njcn.system.api.DictTreeFeignClient;
import com.njcn.system.enums.DicDataEnum;
import com.njcn.system.enums.DicTreeEnum;
import com.njcn.system.pojo.po.DictData;
import com.njcn.system.pojo.vo.DictTreeVO;
import lombok.RequiredArgsConstructor;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import java.io.ByteArrayInputStream;
import java.io.ObjectInputStream;
import java.time.LocalDateTime;
import java.time.format.DateTimeFormatter;
import java.util.*;
import java.util.function.Function;
import java.util.stream.Collectors;
/**
* 高低电压穿越 服务实现类
*
* @author guofeihu
* @since 2024-08-22
*/
@Service
@RequiredArgsConstructor
public class SpThroughServiceImpl extends MppServiceImpl<SpThroughMapper, SpThroughPO> implements SpThroughService {
private final EventDetailFeignClient eventDetailFeignClient;
private final TransientFeignClient transientFeignClient;
private final DeptLineFeignClient deptLineFeignClient;
private final LineFeignClient lineFeignClient;
private final DictTreeFeignClient dictTreeFeignClient;
private final DicDataFeignClient dicDataFeignClient;
@Override
@Transactional(rollbackFor = Exception.class)
public void record() {
DictData dip = dicDataFeignClient.getDicDataByCode(DicDataEnum.VOLTAGE_DIP.getCode()).getData();
DictData rise = dicDataFeignClient.getDicDataByCode(DicDataEnum.VOLTAGE_RISE.getCode()).getData();
DictTreeVO windFarms = dictTreeFeignClient.queryByCode(DicTreeEnum.Wind_Farms.getCode()).getData();
DictTreeVO powerStation = dictTreeFeignClient.queryByCode(DicTreeEnum.Power_Station.getCode()).getData();
LocalDateTime currentTime = LocalDateTime.now();
//获取最新的暂态事件信息(截至目前为止)
//获取带新能源场站的监测点
List<String> lineIds = deptLineFeignClient.getLineByDeptIdAndNewStation(null).getData();
if (CollUtil.isNotEmpty(lineIds)) {
List<LineDetailDataVO> lineDetailDataVOS = lineFeignClient.getLineDetailList(lineIds).getData();
if (CollUtil.isNotEmpty(lineDetailDataVOS)) {
Map<String, LineDetailDataVO> lineDetailDataMap = lineDetailDataVOS.stream().collect(Collectors.toMap(LineDetailDataVO::getLineId, Function.identity()));
EventCountParam param = new EventCountParam();
param.setIds(new ArrayList<>(lineDetailDataMap.keySet()));
LocalDateTime lastTime = getLastTime();
if (ObjectUtil.isNotNull(getLastTime())) {
param.setStartTime(lastTime.format(DateTimeFormatter.ofPattern(DatePattern.NORM_DATETIME_PATTERN)));
}
param.setEndTime(currentTime.format(DateTimeFormatter.ofPattern(DatePattern.NORM_DATETIME_PATTERN)));
List<RmpEventDetailPO> evenStDetailPOS = eventDetailFeignClient.getNewEventDetailByTime(param).getData();
MonitorTerminalParam monitorTerminalParam = new MonitorTerminalParam();
monitorTerminalParam.setSystemType(0);
monitorTerminalParam.setType(0);
for (RmpEventDetailPO rmpEventDetailPO : evenStDetailPOS) {
if (lineDetailDataMap.containsKey(rmpEventDetailPO.getMeasurementPointId())) {
LineDetailDataVO line = lineDetailDataMap.get(rmpEventDetailPO.getMeasurementPointId());
LambdaQueryWrapper<SpThroughPO> lambdaQueryWrapper = new LambdaQueryWrapper();
lambdaQueryWrapper.eq(SpThroughPO::getEventId, rmpEventDetailPO.getEventId())
.eq(SpThroughPO::getEventType, rmpEventDetailPO.getEventType())
.eq(SpThroughPO::getStationType, line.getBigObjType())
.eq(SpThroughPO::getState, 1);
if (this.baseMapper.selectList(lambdaQueryWrapper).isEmpty()) {
//准备高低电压穿越实体bean
SpThroughPO spThroughPO = new SpThroughPO();
spThroughPO.setId(IdUtil.simpleUUID());
spThroughPO.setEventId(rmpEventDetailPO.getEventId());
spThroughPO.setEventType(rmpEventDetailPO.getEventType());
spThroughPO.setStationType(line.getBigObjType());
//默认该事件没有穿越
spThroughPO.setIsOrNot(0);
//设置波形查询的条件:事件ID
monitorTerminalParam.setId(rmpEventDetailPO.getEventId());
//获取RMS波形数据(由于WaveDataDTO为复杂对象所以转成byte数组在进行反序列化)
byte[] bytes = transientFeignClient.getTransientAnalyseWaveToByteArray(monitorTerminalParam).getData();
WaveDataDTO waveDataDTO = null;
try {
ByteArrayInputStream bis = new ByteArrayInputStream(bytes);
ObjectInputStream ois = new ObjectInputStream(bis);
//强转成WaveDataDTO
waveDataDTO = (WaveDataDTO) ois.readObject();
} catch (Exception e) {
e.printStackTrace();
}
//标称电压
if (line.getScale() != null) {
Float voltageLevel = Float.parseFloat(line.getScale());
//格式化数据源
List<List<Float>> newListRmsData = listRmsDataFormat(waveDataDTO);
//暂升事件
if (rmpEventDetailPO.getEventType().equals(rise.getId())) {
//风电场
if (line.getBigObjType().equals(windFarms.getId())) {
if (isThrough(125, 130, 500, voltageLevel.floatValue(), newListRmsData)
&& isThrough(120, 125, 1000, voltageLevel.floatValue(), newListRmsData)
&& isThrough(110, 120, 10000, voltageLevel.floatValue(), newListRmsData)) {
spThroughPO.setIsOrNot(1);
}
}
//光伏电站
if (line.getBigObjType().equals(powerStation.getId())) {
if (isThrough(125, 130, 500, voltageLevel.floatValue(), newListRmsData)
&& isThrough(120, 125, 1000, voltageLevel.floatValue(), newListRmsData)
&& isThrough(110, 120, 10000, voltageLevel.floatValue(), newListRmsData)) {
spThroughPO.setIsOrNot(1);
}
}
}
//暂降事件
if (rmpEventDetailPO.getEventType().equals(dip.getId())) {
//风电场
if (line.getBigObjType().equals(windFarms.getId())) {
if (isThrough(20, -1, 625, voltageLevel.floatValue(), newListRmsData)) {
spThroughPO.setIsOrNot(1);
}
}
//光伏电站
if (line.getBigObjType().equals(powerStation.getId())) {
if (isThrough(0, -1, 150, voltageLevel.floatValue(), newListRmsData)
&& isThrough(20, -1, 625, voltageLevel.floatValue(), newListRmsData)
&& isThrough(20, 90, -1, voltageLevel.floatValue(), newListRmsData)) {
spThroughPO.setIsOrNot(1);
}
}
}
spThroughPO.setCreateTime(currentTime);
this.baseMapper.insert(spThroughPO);
}
}
}
}
}
}
}
private boolean isThrough(int start, int end, int ms, float voltageLevel, List<List<Float>> newListRmsData) {
boolean isThrough = false;
//格式化RMS源数据
float startVoltageLevel = voltageLevel * (start / 100F);
float endVoltageLevel = -1;
if (end != -1) {
endVoltageLevel = voltageLevel * (end / 100F);
}
for (int i = 0; i < newListRmsData.size(); i++) {
for (int j = 1; j < newListRmsData.get(i).size(); j++) {
float curValue = newListRmsData.get(i).get(j);
//当电压达到目标值时
if (endVoltageLevel != -1 && startVoltageLevel < curValue && curValue <= endVoltageLevel) {
isThrough = isContinuity(newListRmsData, i + 1, newListRmsData.get(i).get(0).intValue(), ms, j);
} else if (startVoltageLevel == curValue) {
isThrough = isContinuity(newListRmsData, i + 1, newListRmsData.get(i).get(0).intValue(), ms, j);
}
}
}
return isThrough;
}
private boolean isContinuity(List<List<Float>> newListRmsData, int index, int curms, int ms, int p) {
boolean isContinuity = false;
//记录电压有效毫秒数
Set<Integer> effectiveMs = new HashSet<>();
for (int k = curms + 1; k <= curms + ms; k++) {
effectiveMs.add(k);
}
int count = 0;
for (int i = index; i < newListRmsData.size(); i++) {
for (int j = 0; j < newListRmsData.get(i).size(); j++) {
int curVallue = newListRmsData.get(i).get(0).intValue();
//如果当前相别的电压毫秒数在有效期范围内则记录下数字
if (effectiveMs.contains(curVallue) && checkListIsNull(newListRmsData.get(i), p) != null) {
count++;
}
}
}
if (count >= effectiveMs.size()) {
isContinuity = true;
}
return isContinuity;
}
private Float checkListIsNull(List<Float> list, int index) {
try {
return list.get(index);
} catch (Exception e) {
return null;
}
}
/**
* @param waveDataDTO
* @Description: 格式化RMS数据:将listRmsData中的电压数据取出在根据pt变比组成新的RMS数据
* @return: java.util.List<java.util.List < java.lang.Float>>
* @Author: wr
* @Date: 2025/3/26 19:49
*/
private List<List<Float>> listRmsDataFormat(WaveDataDTO waveDataDTO) {
List<List<Float>> newListRmsData = new ArrayList<>();
List<Integer> indexs = new ArrayList<>();
//根据channelNames取出电压对应listRmsData数据中的数据索引
for (int i = 0; i < waveDataDTO.getChannelNames().size(); i++) {
if (waveDataDTO.getChannelNames().get(i).indexOf("U") != -1) {
indexs.add(i);
}
}
//前端展示的波形图数据来源就是这个所以这边也跟前端保持一致
for (int i = 0; i < waveDataDTO.getListRmsData().size(); i++) {
List<Float> cur = waveDataDTO.getListRmsData().get(i);
List<Float> newCur = new ArrayList<>();
//数组第一个为时间
newCur.add(cur.get(0));
//便利电压数据的索引
for (Integer index : indexs) {
//根据PT变比算出新的数据(前端取的一次值,也是根据pt变比算出的,所以这边和前端保持一致)新增到新的数组中
newCur.add(cur.get(index) * Float.parseFloat((waveDataDTO.getPt() / 1000F) + ""));
}
newListRmsData.add(newCur);
}
return newListRmsData;
}
/**
* 说明:
* 此方法是专门提供给event模块-高低压穿越模块中-获取最新一条暂态事件时间使用
*
* @return
*/
private LocalDateTime getLastTime() {
LambdaQueryWrapper<SpThroughPO> lambdaQueryWrapper = new LambdaQueryWrapper();
lambdaQueryWrapper.orderByDesc(SpThroughPO::getCreateTime);
Page<SpThroughPO> page = new Page<>(1, 1);
List<SpThroughPO> spThroughPOS = this.baseMapper.selectPage(page, lambdaQueryWrapper).getRecords();
if (!spThroughPOS.isEmpty()) {
return spThroughPOS.get(0).getCreateTime();
}
return null;
}
@Override
public SpThroughVO getDataByEventIds(SpThroughParam spThroughParam) {
SpThroughVO spThroughVO = new SpThroughVO();
spThroughVO.setLowPressure("0");
spThroughVO.setHighPressure("0");
String treeId = dicTreeId(spThroughParam);
DictData dip = dicDataFeignClient.getDicDataByCode(DicDataEnum.VOLTAGE_DIP.getCode()).getData();
if (ObjectUtil.isNotNull(dip)) {
spThroughVO.setHighPressure(eventCount(spThroughParam, treeId, dip) + "");
}
DictData rise = dicDataFeignClient.getDicDataByCode(DicDataEnum.VOLTAGE_RISE.getCode()).getData();
if (ObjectUtil.isNotNull(rise)) {
spThroughVO.setLowPressure(eventCount(spThroughParam, treeId, rise) + "");
}
return spThroughVO;
}
private Integer eventCount(SpThroughParam spThroughParam, String dictTreeId, DictData rise) {
LambdaQueryWrapper<SpThroughPO> lowLambdaQueryWrapper = new LambdaQueryWrapper();
lowLambdaQueryWrapper.in(SpThroughPO::getEventId, spThroughParam.getEventIds())
.eq(SpThroughPO::getIsOrNot, 1)
.eq(SpThroughPO::getStationType, dictTreeId)
.eq(SpThroughPO::getState, 1)
.eq(SpThroughPO::getEventType, rise.getId());
return this.baseMapper.selectCount(lowLambdaQueryWrapper);
}
/**
* 说明:
* 此方法是专门提供给event模块-高低压穿越模块中-根据区域获取暂态事件列表使用
* 根据区域获取各个子区域高低电压穿越次数是基于sp_through表中记录来的 那么在根据区域获取暂态事件列表数据也应该基于sp_through表中记录来
* 因为如果不基于sp_through表中记录来 那么根据区域获取暂态事件可能数据非常多且可能一部分的事件数据并没有被定时任务(record方法)所执行
*
* @param spThroughParam
* @return
*/
@Override
public List<String> formatEventIds(SpThroughParam spThroughParam) {
LambdaQueryWrapper<SpThroughPO> lambdaQueryWrapper = new LambdaQueryWrapper();
lambdaQueryWrapper.in(SpThroughPO::getEventId, spThroughParam.getEventIds())
.eq(SpThroughPO::getIsOrNot, 1)
.eq(SpThroughPO::getStationType, dicTreeId(spThroughParam))
.eq(SpThroughPO::getState, 1);
List<SpThroughPO> spThroughPOS = this.baseMapper.selectList(lambdaQueryWrapper);
return spThroughPOS.stream().map(SpThroughPO::getEventId).collect(Collectors.toList());
}
private String dicTreeId(SpThroughParam spThroughParam) {
String dictTreeId = "";
if ("1".equals(spThroughParam.getStationType())) {
DictTreeVO windFarms = dictTreeFeignClient.queryByCode(DicTreeEnum.Wind_Farms.getCode()).getData();
if (ObjectUtil.isNotNull(windFarms)) {
dictTreeId = windFarms.getId();
}
} else {
DictTreeVO powerStation = dictTreeFeignClient.queryByCode(DicTreeEnum.Power_Station.getCode()).getData();
if (ObjectUtil.isNotNull(powerStation)) {
dictTreeId = powerStation.getId();
}
}
return dictTreeId;
}
}

View File

@@ -1,26 +0,0 @@
package com.njcn.prepare.harmonic.service.mysql.event;
import com.github.jeffreyning.mybatisplus.service.IMppService;
import com.njcn.harmonic.pojo.vo.PowerStatisticsTargetVO;
import com.njcn.prepare.harmonic.pojo.param.RActivePowerRangeParam;
import com.njcn.prepare.harmonic.pojo.po.RActivePowerRangePO;
import java.util.List;
/**
* 有功功率趋势 服务类
* @author guofeihu
* @since 2024-08-22
*/
public interface RActivePowerRangeService extends IMppService<RActivePowerRangePO> {
/**
* 有功功率趋势记录(用于定时任务)
*/
List<PowerStatisticsTargetVO> record(RActivePowerRangeParam rActivePowerRangeParam);
/**
* 根据监测点ID及时间获取有功功率趋势
*/
RActivePowerRangePO getDataByLineId(String lineId,String startTime,String endTime);
}

View File

@@ -1,31 +0,0 @@
package com.njcn.prepare.harmonic.service.mysql.event;
import com.github.jeffreyning.mybatisplus.service.IMppService;
import com.njcn.prepare.harmonic.pojo.param.SpThroughParam;
import com.njcn.prepare.harmonic.pojo.po.SpThroughPO;
import com.njcn.prepare.harmonic.pojo.vo.SpThroughVO;
import java.util.List;
/**
* 高低电压穿越 服务类
* @author guofeihu
* @since 2024-08-22
*/
public interface SpThroughService extends IMppService<SpThroughPO> {
/**
* 高低电压穿越记录(用于定时任务)
*/
void record();
/**
* 根据事件ID集合及能源站类型获取高低电压穿越次数
*/
SpThroughVO getDataByEventIds(SpThroughParam spThroughParam);
/**
* 根据原有的事件集合进行过滤
*/
List<String> formatEventIds(SpThroughParam spThroughParam);
}