package com.ruoyi.other.service.impl;
|
|
import com.alibaba.fastjson.JSONArray;
|
import com.alibaba.fastjson2.JSONObject;
|
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
|
import com.ruoyi.common.core.exception.ServiceException;
|
import com.ruoyi.common.core.utils.StringUtils;
|
import com.ruoyi.common.core.web.page.PageInfo;
|
import com.ruoyi.other.api.domain.TStationInfo;
|
import com.ruoyi.other.mapper.TStationInfoMapper;
|
import com.ruoyi.other.service.TStationCollectService;
|
import com.ruoyi.other.service.TStationEarnService;
|
import com.ruoyi.other.service.TStationInfoService;
|
import com.ruoyi.other.query.StationInfoQuery;
|
import com.ruoyi.other.util.KsolarUtils;
|
import com.ruoyi.other.util.HuWeiUtils;
|
import com.ruoyi.other.vo.StationInfoStatusVO;
|
import lombok.extern.slf4j.Slf4j;
|
import org.apache.commons.collections4.CollectionUtils;
|
import org.springframework.beans.factory.annotation.Autowired;
|
import org.springframework.stereotype.Service;
|
import org.springframework.transaction.annotation.Transactional;
|
|
import java.math.BigDecimal;
|
import java.time.LocalDate;
|
import java.time.LocalDateTime;
|
import java.time.OffsetDateTime;
|
import java.time.ZonedDateTime;
|
import java.time.format.DateTimeFormatter;
|
import java.time.format.DateTimeParseException;
|
import java.util.*;
|
import java.util.function.Function;
|
import java.util.stream.Collectors;
|
|
/**
|
* 电站信息服务实现。
|
*/
|
@Service
|
@Slf4j
|
public class TStationInfoServiceImpl
|
extends ServiceImpl<TStationInfoMapper, TStationInfo>
|
implements TStationInfoService {
|
|
@Autowired
|
private TStationCollectService collectService;
|
@Autowired
|
private TStationEarnService stationEarnService;
|
|
@Autowired
|
private HuWeiUtils huWeiUtils;
|
|
/**
|
* 每天同步科士达数据到数据库
|
*/
|
@Transactional(rollbackFor = Exception.class)
|
public void syncKsolarDataTask() {
|
String token = KsolarUtils.token();
|
//JSONObject statusJsonObj = KsolarUtils.getListStatus(token);
|
|
log.info("-------1开始同步科士达-电站列表信息----");
|
// 电站列表
|
JSONArray listInfoJsonArray = KsolarUtils.getStationListInfo(1, 1000, token);
|
// 电站基本信息列表
|
JSONArray listBaseJsonArray = KsolarUtils.getStationListBase(1, 1000, token);
|
List<TStationInfo> stationInfoList = build(listInfoJsonArray, listBaseJsonArray);
|
|
if(CollectionUtils.isNotEmpty(stationInfoList)) {
|
// 去除stationInfoList中的重复stationId
|
Map<String, TStationInfo> stationMap = stationInfoList.stream().filter(item -> StringUtils.isNotEmpty(item.getStationId()))
|
.collect(Collectors.toMap(TStationInfo::getStationId, Function.identity(), (o1, o2) -> o2));
|
|
stationInfoList = new ArrayList<>(stationMap.values());
|
|
// 查询数据库已有数据
|
List<TStationInfo> existingStationList = lambdaQuery().in(TStationInfo::getStationId, stationMap.keySet()).list();
|
|
// 转Map,方便查找
|
Map<String, TStationInfo> existingMap = existingStationList.stream().collect(Collectors.toMap(TStationInfo::getStationId, Function.identity()));
|
|
List<TStationInfo> insertList = new ArrayList<>();
|
List<TStationInfo> updateList = new ArrayList<>();
|
|
for (TStationInfo station : stationInfoList) {
|
TStationInfo dbStation = existingMap.get(station.getStationId());
|
if (dbStation == null) {
|
// 数据库不存在
|
insertList.add(station);
|
} else {
|
// 数据库存在,需要更新;保留数据库主键,否则updateBatchById无法更新
|
station.setId(dbStation.getId());
|
updateList.add(station);
|
}
|
}
|
// 批量新增
|
if (CollectionUtils.isNotEmpty(insertList)) {
|
saveBatch(insertList);
|
}
|
// 批量更新
|
if (CollectionUtils.isNotEmpty(updateList)) {
|
updateBatchById(updateList);
|
}
|
}
|
log.info("-------1结束同步科士达-电站列表信息----");
|
|
log.info("-------2开始同步科士达-逆变器列表----");
|
// 逆变器列表
|
JSONArray collectBaseList = KsolarUtils.getCollectBaseList(1, 1000, token);
|
collectService.saveCollectBaseList(collectBaseList);
|
log.info("-------2结束同步科士达-逆变器列表----");
|
|
log.info("-------3开始同步科士达-电站的电量和收益统计查询----");
|
String startDateStr = buildSyncStartDate(LocalDate.now());
|
String endDateStr = LocalDateTime.now().format(DateTimeFormatter.ofPattern("yyyy-MM-dd"));
|
JSONArray stationEarnList = KsolarUtils.getStationElecList(startDateStr, endDateStr, token);
|
stationEarnService.saveStationEarnList(stationEarnList);
|
log.info("-------3结束同步科士达-电站的电量和收益统计查询----");
|
}
|
|
|
/**
|
* 根据电站列表信息和电站基础信息批量构建电站对象。
|
* 两个数组通过 stationId 进行关联。
|
*/
|
public List<TStationInfo> build(JSONArray listInfoJsonArray, JSONArray listBaseJsonArray) {
|
if (listInfoJsonArray == null || listInfoJsonArray.isEmpty()) {
|
log.error("电站列表信息获取第三方API数据为空!");
|
return null;
|
}
|
Map<String, JSONObject> baseMap = buildBaseMap(listBaseJsonArray);
|
List<TStationInfo> stationInfoList = new ArrayList<>(listInfoJsonArray.size());
|
for (Object item : listInfoJsonArray) {
|
JSONObject info = JSONObject.parseObject(item.toString());
|
String stationId = info.getString("stationId");
|
if (StringUtils.isBlank(stationId)) {
|
log.error("电站列表信息中的stationId不能为空!");
|
continue;
|
}
|
stationInfoList.add(buildStationInfo(info, baseMap.get(stationId)));
|
}
|
return stationInfoList;
|
}
|
|
private TStationInfo buildStationInfo(JSONObject info, JSONObject base) {
|
String stationId = info.getString("stationId");
|
TStationInfo stationInfo = new TStationInfo();
|
stationInfo.setPlatformId(0L);
|
stationInfo.setStationId(stationId);
|
stationInfo.setStationName(info.getString("stationName"));
|
stationInfo.setStationType(info.getString("stationType"));
|
stationInfo.setRunStatus(info.getString("status"));
|
stationInfo.setRealtimePower(toBigDecimal(info, "powerInter"));
|
stationInfo.setInstalledCapacity(toBigDecimal(info, "installCapacity"));
|
stationInfo.setDailyGeneration(toBigDecimal(info, "dayGeneration"));
|
stationInfo.setDeviceCount(info.getInteger("collects"));
|
stationInfo.setAddress(info.getString("address"));
|
stationInfo.setStationImage(info.getString("stationImage"));
|
|
if (base != null) {
|
stationInfo.setStationName(firstNotBlank(base.getString("stationName"), stationInfo.getStationName()));
|
stationInfo.setInstalledCapacity(firstNotNull(
|
toBigDecimal(base, "installCapacity"), stationInfo.getInstalledCapacity()));
|
stationInfo.setAreaName(base.getString("areaName"));
|
stationInfo.setCityName(base.getString("cityName"));
|
stationInfo.setElecPrice(base.getString("elecPrice"));
|
stationInfo.setLatitude(base.getString("latitude"));
|
stationInfo.setLongitude(base.getString("longitude"));
|
stationInfo.setPhone(firstNotBlank(base.getString("Phone"), base.getString("phone")));
|
stationInfo.setProvinceName(base.getString("provinceName"));
|
stationInfo.setAddress(firstNotBlank(
|
base.getString("stationAddressDetail"), stationInfo.getAddress()));
|
stationInfo.setLoanStatus(base.getInteger("loanStatus"));
|
stationInfo.setGridStatus(Objects.equals(stationInfo.getLoanStatus(), 3) ? "1" : "0");
|
stationInfo.setDataTime(parseDataTime(base.getString("saveTime")));
|
}
|
|
stationInfo.setDataSource(2);
|
stationInfo.setSyncTime(LocalDateTime.now());
|
fillDefaults(stationInfo);
|
return stationInfo;
|
}
|
|
@Override
|
@Transactional(rollbackFor = Exception.class)
|
public boolean addStationInfo(TStationInfo stationInfo) {
|
validate(stationInfo);
|
stationInfo.setStationId("1"+System.currentTimeMillis());
|
stationInfo.setDataSource(1);
|
if (lambdaQuery().eq(TStationInfo::getPlatformId,
|
stationInfo.getPlatformId() == null ? 0L : stationInfo.getPlatformId())
|
.eq(TStationInfo::getStationId, stationInfo.getStationId()).count() > 0) {
|
throw new ServiceException("该平台下的电站信息已存在");
|
}
|
fillDefaults(stationInfo);
|
stationInfo.setId(null);
|
stationInfo.setCreateTime(LocalDateTime.now());
|
stationInfo.setUpdateTime(LocalDateTime.now());
|
return save(stationInfo);
|
}
|
|
@Override
|
public PageInfo<TStationInfo> pageList(StationInfoQuery query) {
|
if (query == null) query = new StationInfoQuery();
|
PageInfo<TStationInfo> page = new PageInfo<>(query.getPageCurr(), query.getPageSize());
|
lambdaQuery()
|
.eq(query.getPlatformId() != null, TStationInfo::getPlatformId, query.getPlatformId())
|
.like(StringUtils.isNotBlank(query.getStationName()), TStationInfo::getStationName, query.getStationName())
|
.eq(StringUtils.isNotBlank(query.getStationType()), TStationInfo::getStationType, query.getStationType())
|
.eq(StringUtils.isNotBlank(query.getRunStatus()), TStationInfo::getRunStatus, query.getRunStatus())
|
.eq(StringUtils.isNotBlank(query.getGridStatus()), TStationInfo::getGridStatus, query.getGridStatus())
|
.orderByAsc(TStationInfo::getSortOrder).orderByDesc(TStationInfo::getCreateTime).page(page);
|
return page;
|
}
|
|
@Override
|
@Transactional(rollbackFor = Exception.class)
|
public boolean updateStationInfo(TStationInfo stationInfo) {
|
if (stationInfo == null || stationInfo.getId() == null) throw new ServiceException("电站信息ID不能为空");
|
TStationInfo old = getById(stationInfo.getId());
|
if (old == null) throw new ServiceException("电站信息不存在");
|
if (stationInfo.getStationId() != null && lambdaQuery()
|
.eq(TStationInfo::getPlatformId, stationInfo.getPlatformId() == null ? old.getPlatformId() : stationInfo.getPlatformId())
|
.eq(TStationInfo::getStationId, stationInfo.getStationId()).ne(TStationInfo::getId, stationInfo.getId()).count() > 0) {
|
throw new ServiceException("该平台下的电站信息已存在");
|
}
|
stationInfo.setCreateBy(null); stationInfo.setCreateTime(null); stationInfo.setDelFlag(null);
|
stationInfo.setUpdateTime(LocalDateTime.now());
|
return updateById(stationInfo);
|
}
|
|
private void validate(TStationInfo stationInfo) {
|
if (stationInfo == null) {
|
throw new ServiceException("电站信息参数不能为空");
|
}
|
if (StringUtils.isBlank(stationInfo.getStationName())) {
|
throw new ServiceException("电站名称不能为空");
|
}
|
}
|
|
private void fillDefaults(TStationInfo stationInfo) {
|
stationInfo.setPlatformId(stationInfo.getPlatformId() == null ? 0L : stationInfo.getPlatformId());
|
stationInfo.setStationType(StringUtils.isBlank(stationInfo.getStationType()) ? "1" : stationInfo.getStationType());
|
stationInfo.setRunStatus(StringUtils.isBlank(stationInfo.getRunStatus()) ? "0" : stationInfo.getRunStatus());
|
stationInfo.setInstalledCapacity(stationInfo.getInstalledCapacity() == null
|
? BigDecimal.ZERO : stationInfo.getInstalledCapacity());
|
stationInfo.setRealtimePower(stationInfo.getRealtimePower() == null
|
? BigDecimal.ZERO : stationInfo.getRealtimePower());
|
stationInfo.setDeviceCount(stationInfo.getDeviceCount() == null ? 0 : stationInfo.getDeviceCount());
|
stationInfo.setDailyGeneration(stationInfo.getDailyGeneration() == null
|
? BigDecimal.ZERO : stationInfo.getDailyGeneration());
|
stationInfo.setGridStatus(StringUtils.isBlank(stationInfo.getGridStatus()) ? "0" : stationInfo.getGridStatus());
|
stationInfo.setSortOrder(stationInfo.getSortOrder() == null ? 0 : stationInfo.getSortOrder());
|
stationInfo.setCreateBy(StringUtils.defaultString(stationInfo.getCreateBy()));
|
stationInfo.setUpdateBy(StringUtils.defaultString(stationInfo.getUpdateBy()));
|
stationInfo.setDelFlag("0");
|
}
|
|
private Map<String, JSONObject> buildBaseMap(JSONArray jsonArray) {
|
Map<String, JSONObject> baseMap = new HashMap<>();
|
if (jsonArray != null) {
|
for (Object item : jsonArray) {
|
JSONObject object = JSONObject.parseObject(item.toString());
|
String stationId = object.getString("stationId");
|
if (StringUtils.isNotBlank(stationId)) {
|
baseMap.put(stationId, object);
|
}
|
}
|
}
|
return baseMap;
|
}
|
|
static String buildSyncStartDate(LocalDate date) {
|
return date.withDayOfYear(1).format(DateTimeFormatter.ISO_LOCAL_DATE) + " 00:00:00";
|
}
|
|
private Long parseStationId(String stationId) {
|
try {
|
return Long.valueOf(stationId);
|
} catch (NumberFormatException exception) {
|
log.error("stationId格式不正确:" + stationId);
|
return null;
|
}
|
}
|
|
private BigDecimal toBigDecimal(JSONObject object, String key) {
|
if (object == null || object.get(key) == null || StringUtils.isBlank(object.getString(key))) {
|
return null;
|
}
|
try {
|
return new BigDecimal(object.getString(key));
|
} catch (NumberFormatException exception) {
|
log.error(key + "格式不正确:" + object.getString(key));
|
return null;
|
}
|
}
|
|
private LocalDateTime parseDataTime(String value) {
|
if (StringUtils.isBlank(value)) {
|
return null;
|
}
|
DateTimeFormatter[] dateTimeFormatters = {
|
DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss"),
|
DateTimeFormatter.ofPattern("yyyy-MM-dd'T'HH:mm:ss")
|
};
|
for (DateTimeFormatter formatter : dateTimeFormatters) {
|
try {
|
return LocalDateTime.parse(value, formatter);
|
} catch (DateTimeParseException ignored) {
|
// 尝试下一个时间格式
|
}
|
}
|
try {
|
return LocalDate.parse(value, DateTimeFormatter.ofPattern("yyyy-MM-dd")).atStartOfDay();
|
} catch (DateTimeParseException exception) {
|
log.error("saveTime格式不正确:" + value);
|
return null;
|
}
|
}
|
|
private LocalDateTime parseHuaweiDateTime(String value) {
|
if (StringUtils.isBlank(value)) {
|
return null;
|
}
|
try {
|
return OffsetDateTime.parse(value).toLocalDateTime();
|
} catch (DateTimeParseException ignored) {
|
try {
|
return ZonedDateTime.parse(value).toLocalDateTime();
|
} catch (DateTimeParseException ignoredAgain) {
|
return parseDataTime(value);
|
}
|
}
|
}
|
|
private String firstNotBlank(String preferred, String fallback) {
|
return StringUtils.isNotBlank(preferred) ? preferred : fallback;
|
}
|
|
private <T> T firstNotNull(T preferred, T fallback) {
|
return preferred != null ? preferred : fallback;
|
}
|
|
/**
|
* 实时获取电站状态
|
*/
|
public StationInfoStatusVO getStationStatus() {
|
StationInfoStatusVO statusVO = new StationInfoStatusVO();
|
String token = KsolarUtils.token();
|
JSONObject statusJsonObj = KsolarUtils.getListStatus(token);
|
JSONObject earnJsonObj = KsolarUtils.getListEarn("", token);
|
if(Objects.nonNull(statusJsonObj)) {
|
statusVO.setAlarm(statusJsonObj.getInteger("alarm"));
|
statusVO.setOffline(statusJsonObj.getInteger("offline"));
|
statusVO.setOnline(statusJsonObj.getInteger("online"));
|
statusVO.setTotal(statusJsonObj.getInteger("total"));
|
}
|
if(Objects.nonNull(earnJsonObj)) {
|
statusVO.setRealPower(earnJsonObj.getDouble("realPower"));
|
statusVO.setDayGeneration(earnJsonObj.getDouble("dayGeneration"));
|
}
|
// 统计电站数量
|
List<TStationInfo> stationInfoList = lambdaQuery().eq(TStationInfo::getDelFlag, "0").list();
|
if(CollectionUtils.isNotEmpty(stationInfoList)) {
|
statusVO.setStationCount(stationInfoList.size());
|
List<TStationInfo> onStatusList = stationInfoList.stream().filter(s -> Objects.nonNull(s.getLoanStatus()) && s.getLoanStatus() == 3).collect(Collectors.toList());
|
statusVO.setOnStatusCount(onStatusList.size());
|
statusVO.setOffStatusCount(stationInfoList.size() - onStatusList.size());
|
}
|
// 电站状态数量加上非科士达的数据
|
List<TStationInfo> noKeShiDaList = stationInfoList.stream().filter(s -> s.getPlatformId() != 0).collect(Collectors.toList());
|
statusVO.setTotal(statusVO.getTotal() + noKeShiDaList.size());
|
statusVO.setOnline(statusVO.getOnline() + noKeShiDaList.size());
|
return statusVO;
|
}
|
|
/**
|
* 根据ids删除数据时,校验示范存在第三方同步的数据,第三方同步的数据不允许删除
|
* @param ids 数据id
|
* @return true可以删除,false不可以删除
|
*/
|
public Boolean validateDelete(Long[] ids) {
|
if(ids != null && ids.length > 0) {
|
List<Long> idList = Arrays.stream(ids).collect(Collectors.toList());
|
List<TStationInfo> infoList = lambdaQuery().eq(TStationInfo::getDataSource, 2).in(TStationInfo::getId, idList).list();
|
if(CollectionUtils.isNotEmpty(infoList) && !infoList.isEmpty()) {
|
return false;
|
}
|
}
|
return true;
|
}
|
|
/**
|
* 同步华为 FusionSolar 电站数据。
|
* 电站编号 plantCode 作为系统中的 stationId,仅插入数据库中不存在的电站。
|
*/
|
@Transactional(rollbackFor = Exception.class)
|
public void syncHuaWeiDataTask() {
|
log.info("-------1、开始同步华为电站列表信息----");
|
String token = huWeiUtils.getXsrfToken();
|
JSONArray stationArray = huWeiUtils.getStations(1, token);
|
Set<String> stationIds = new HashSet<>();
|
if (CollectionUtils.isNotEmpty(stationArray)) {
|
List<TStationInfo> insertList = new ArrayList<>();
|
huaWeiBuild(stationArray, stationIds, insertList);
|
|
if (CollectionUtils.isNotEmpty(insertList)) {
|
List<TStationInfo> existing = lambdaQuery().eq(TStationInfo::getPlatformId, 1L).in(TStationInfo::getStationId, stationIds).list();
|
Set<String> existingIds = existing.stream().map(TStationInfo::getStationId).collect(Collectors.toSet());
|
insertList.removeIf(item -> existingIds.contains(item.getStationId()));
|
if (CollectionUtils.isNotEmpty(insertList)) {
|
saveBatch(insertList);
|
}
|
}
|
log.info("-------1、结束同步华为电站列表信息,本次新增{}条----", insertList.size());
|
}
|
|
log.info("-------2、开始同步华为设备列表信息----");
|
if(CollectionUtils.isNotEmpty(stationIds)) {
|
String codes = String.join(",", stationIds);
|
JSONArray devList = huWeiUtils.getDevList(codes, token);
|
collectService.saveCollectHuaWeiList(devList);
|
}
|
|
log.info("-------3、开始同步华为电站日数据信息----");
|
List<TStationInfo> existInfos = lambdaQuery().eq(TStationInfo::getPlatformId, 1L).list();
|
Set<String> existIds = existInfos.stream().map(TStationInfo::getStationId).collect(Collectors.toSet());
|
if(CollectionUtils.isNotEmpty(existIds)) {
|
String codes = String.join(",", existIds);
|
JSONArray stationDayList = huWeiUtils.getKpiStationDay(codes, System.currentTimeMillis(), token);
|
stationEarnService.saveStationHuaWeiList(stationDayList);
|
}
|
log.info("-------3、结束同步华为电站日数据信息----");
|
|
|
}
|
|
public void huaWeiBuild(JSONArray stationArray, Set<String> stationIds, List<TStationInfo> insertList) {
|
for (Object item : stationArray) {
|
JSONObject json = JSONObject.parseObject(item.toString());
|
String stationId = json.getString("plantCode");
|
if (StringUtils.isBlank(stationId) || !stationIds.add(stationId)) {
|
continue;
|
}
|
TStationInfo info = new TStationInfo();
|
info.setPlatformId(1L);
|
info.setStationId(stationId);
|
info.setStationName(json.getString("plantName"));
|
info.setStationType("1");
|
info.setRunStatus("0");
|
info.setInstalledCapacity(toBigDecimal(json, "capacity"));
|
info.setContactName(json.getString("contactPerson"));
|
info.setPhone(json.getString("contactMethod"));
|
info.setLatitude(json.getString("latitude"));
|
info.setLongitude(json.getString("longitude"));
|
info.setAddress(json.getString("plantAddress"));
|
LocalDateTime gridTime = parseHuaweiDateTime(json.getString("gridConnectionDate"));
|
info.setDataTime(gridTime);
|
info.setLoanStatus(gridTime != null && gridTime.isBefore(LocalDateTime.now()) ? 3 : 1);
|
info.setGridStatus(info.getLoanStatus() == 3 ? "1" : "0");
|
info.setDataSource(2);
|
info.setSyncTime(LocalDateTime.now());
|
info.setCreateTime(LocalDateTime.now());
|
info.setUpdateTime(LocalDateTime.now());
|
fillDefaults(info);
|
insertList.add(info);
|
}
|
}
|
|
}
|