add 新增运营端小程序查询站点及充电枪状态

This commit is contained in:
YAS\29473
2025-12-31 08:56:45 +08:00
parent 38d0d05327
commit fe80482e6b
8 changed files with 342 additions and 0 deletions

View File

@@ -5,10 +5,12 @@ import com.google.common.collect.ImmutableMap;
import com.jsowell.common.core.controller.BaseController;
import com.jsowell.common.exception.BusinessException;
import com.jsowell.common.response.RestApiResponse;
import com.jsowell.pile.dto.business.QueryStationWithConnectorStatusDTO;
import com.jsowell.pile.dto.business.StationBusinessAnalyzeInfoDTO;
import com.jsowell.pile.dto.business.StationStatisticsInfoDTO;
import com.jsowell.pile.service.OrderBasicInfoService;
import com.jsowell.pile.service.PileStationInfoService;
import com.jsowell.common.core.page.PageResponse;
import com.jsowell.pile.vo.uniapp.business.StationBusinessAnalyzeInfoVO;
import com.jsowell.pile.vo.uniapp.business.StationStatisticsInfosVO;
import org.springframework.beans.factory.annotation.Autowired;
@@ -151,4 +153,24 @@ public class BusinessStationInfoController extends BaseController {
return response;
}
/**
* 运营端小程序查询站点及充电枪状态
* 支持通过站点ID或站点名称查询不传则查询全部站点
* @param dto 查询条件
* @return 站点列表及充电枪状态统计
*/
@PostMapping("/queryStationWithConnectorStatus")
public RestApiResponse<?> queryStationWithConnectorStatus(@RequestBody QueryStationWithConnectorStatusDTO dto) {
RestApiResponse<?> response = null;
try {
PageResponse pageResponse = pileStationInfoService.queryStationWithConnectorStatus(dto);
response = new RestApiResponse<>(pageResponse);
} catch (Exception e) {
logger.error("查询站点及充电枪状态 error", e);
response = new RestApiResponse<>(e);
}
logger.info("查询站点及充电枪状态 params:{}, result:{}", JSONObject.toJSONString(dto), response);
return response;
}
}

View File

@@ -335,6 +335,11 @@ public class CacheConstants {
*/
public static final String PILE_HARDWARE_FAULT = "pile_hardware_fault:";
/**
* 充电枪状态变更时间戳(用于计算状态持续时长)
*/
public static final String PILE_CONNECTOR_STATUS_CHANGE_TIME = "pile_connector_status_change_time:";
/**
* 充电桩sn生成 key
*/

View File

@@ -0,0 +1,39 @@
package com.jsowell.pile.dto.business;
import lombok.AllArgsConstructor;
import lombok.Builder;
import lombok.Data;
import lombok.NoArgsConstructor;
/**
* 运营端小程序查询站点及充电枪状态DTO
*
* @author Auto
* @Date 2024/12/19
*/
@Data
@AllArgsConstructor
@NoArgsConstructor
@Builder
public class QueryStationWithConnectorStatusDTO {
/**
* 站点id可选
*/
private String stationId;
/**
* 站点名称(可选,支持模糊查询)
*/
private String stationName;
/**
* 页码默认1
*/
private int pageNum;
/**
* 每页条数默认10
*/
private int pageSize;
}

View File

@@ -6,6 +6,7 @@ import com.jsowell.pile.dto.FastCreateStationDTO;
import com.jsowell.pile.dto.QueryStationDTO;
import com.jsowell.pile.dto.QueryStationInfoDTO;
import com.jsowell.pile.dto.amap.GetStationInfoDTO;
import com.jsowell.pile.dto.business.QueryStationWithConnectorStatusDTO;
import com.jsowell.pile.dto.business.StationBusinessAnalyzeInfoDTO;
import com.jsowell.pile.dto.business.StationStatisticsInfoDTO;
import com.jsowell.pile.dto.lutongyunting.BindParkingPlatformDTO;
@@ -14,6 +15,7 @@ import com.jsowell.pile.vo.base.ThirdPartyStationInfoVO;
import com.jsowell.pile.vo.ningxiajiaotou.NXJTStationInfoVO;
import com.jsowell.pile.vo.uniapp.business.StationBusinessAnalyzeInfoVO;
import com.jsowell.pile.vo.uniapp.business.StationStatisticsInfosVO;
import com.jsowell.pile.vo.uniapp.business.StationWithConnectorStatusVO;
import com.jsowell.pile.vo.web.PileStationVO;
import com.jsowell.pile.vo.web.StationSelectVO;
@@ -215,4 +217,11 @@ public interface PileStationInfoService {
* @return
*/
PageResponse queryUserFrequentedStation(QueryStationDTO dto);
/**
* 运营端小程序查询站点及充电枪状态
* @param dto 查询条件
* @return 站点列表及充电枪状态统计
*/
PageResponse queryStationWithConnectorStatus(QueryStationWithConnectorStatusDTO dto);
}

View File

@@ -773,6 +773,23 @@ public class PileConnectorInfoServiceImpl implements PileConnectorInfoService {
deleteRedisByPileSnOrPileConnectorCode(pileSn, pileConnectorCode);
redisCache.setCacheObject(redisKey, status, CacheConstants.cache_expire_time_6m);
// 记录状态变更时间戳(用于计算状态持续时长)
// 只记录需要计算时长的状态:故障、离线、占用(未充电)、挂起(预约锁定)
if (StringUtils.equals(status, PileConnectorDataBaseStatusEnum.FAULT.getValue())
|| StringUtils.equals(status, PileConnectorDataBaseStatusEnum.OFF_NETWORK.getValue())
|| StringUtils.equals(status, PileConnectorDataBaseStatusEnum.OCCUPIED_NOT_CHARGED.getValue())
|| StringUtils.equals(status, PileConnectorDataBaseStatusEnum.OCCUPIED_RESERVED_LOCK.getValue())) {
String statusChangeTimeKey = CacheConstants.PILE_CONNECTOR_STATUS_CHANGE_TIME + pileConnectorCode;
String now = DateUtils.getDateTime();
redisCache.setCacheObject(statusChangeTimeKey, now, CacheConstants.cache_expire_time_30d);
} else {
// 状态变更为空闲或充电中时,删除状态变更时间戳
String statusChangeTimeKey = CacheConstants.PILE_CONNECTOR_STATUS_CHANGE_TIME + pileConnectorCode;
if (redisCache.hasKey(statusChangeTimeKey)) {
redisCache.deleteObject(statusChangeTimeKey);
}
}
// 异步放缓存
CompletableFuture.runAsync(() -> statusChange(pileConnectorCode), executor);
}

View File

@@ -16,11 +16,13 @@ import com.jsowell.common.enums.ykc.ReturnCodeEnum;
import com.jsowell.common.exception.BusinessException;
import com.jsowell.common.util.*;
import com.jsowell.common.util.ip.AddressUtils;
import com.jsowell.common.core.domain.ykc.RealTimeMonitorData;
import com.jsowell.pile.domain.*;
import com.jsowell.pile.dto.FastCreateStationDTO;
import com.jsowell.pile.dto.QueryStationDTO;
import com.jsowell.pile.dto.QueryStationInfoDTO;
import com.jsowell.pile.dto.amap.GetStationInfoDTO;
import com.jsowell.pile.dto.business.QueryStationWithConnectorStatusDTO;
import com.jsowell.pile.dto.business.StationBusinessAnalyzeInfoDTO;
import com.jsowell.pile.dto.business.StationStatisticsInfoDTO;
import com.jsowell.pile.dto.lutongyunting.BindParkingPlatformDTO;
@@ -35,6 +37,7 @@ import com.jsowell.pile.vo.uniapp.business.BusinessOrderDetailInfoVO;
import com.jsowell.pile.vo.uniapp.business.StationBusinessAnalyzeInfoVO;
import com.jsowell.pile.vo.uniapp.business.StationOrderQuantityInfoVO;
import com.jsowell.pile.vo.uniapp.business.StationStatisticsInfosVO;
import com.jsowell.pile.vo.uniapp.business.StationWithConnectorStatusVO;
import com.jsowell.pile.vo.uniapp.customer.CurrentTimePriceDetails;
import com.jsowell.pile.vo.web.BillingTemplateVO;
import com.jsowell.pile.vo.web.PileStationVO;
@@ -1623,4 +1626,165 @@ public class PileStationInfoServiceImpl implements PileStationInfoService {
}
return uniAppQueryStationInfoListV2(dto);
}
/**
* 运营端小程序查询站点及充电枪状态
* @param dto 查询条件
* @return 站点列表及充电枪状态统计
*/
@Override
public PageResponse queryStationWithConnectorStatus(QueryStationWithConnectorStatusDTO dto) {
// 获取当前登录账号的运营商权限
List<MerchantInfoVO> merchantInfoVOList = UserUtils.getMerchantInfoVOList();
if (CollectionUtils.isEmpty(merchantInfoVOList)) {
throw new BusinessException(ReturnCodeEnum.CODE_SELECT_INFO_IS_NULL);
}
List<String> merchantIds = merchantInfoVOList.stream()
.map(MerchantInfoVO::getMerchantId)
.collect(Collectors.toList());
// 根据权限查询站点列表
List<PileStationInfo> allStations = getStationInfosByMerchantIds(merchantIds);
if (CollectionUtils.isEmpty(allStations)) {
throw new BusinessException(ReturnCodeEnum.CODE_SELECT_INFO_IS_NULL);
}
// 根据站点ID或站点名称过滤
List<PileStationInfo> filteredStations = allStations;
if (StringUtils.isNotBlank(dto.getStationId())) {
filteredStations = allStations.stream()
.filter(s -> String.valueOf(s.getId()).equals(dto.getStationId()))
.collect(Collectors.toList());
} else if (StringUtils.isNotBlank(dto.getStationName())) {
filteredStations = allStations.stream()
.filter(s -> s.getStationName() != null && s.getStationName().contains(dto.getStationName()))
.collect(Collectors.toList());
}
if (CollectionUtils.isEmpty(filteredStations)) {
throw new BusinessException(ReturnCodeEnum.CODE_SELECT_INFO_IS_NULL);
}
// 分页处理
int pageNum = dto.getPageNum() == 0 ? 1 : dto.getPageNum();
int pageSize = dto.getPageSize() == 0 ? 10 : dto.getPageSize();
PageHelper.startPage(pageNum, pageSize);
// 构建返回结果
List<StationWithConnectorStatusVO> resultList = new ArrayList<>();
for (PileStationInfo station : filteredStations) {
String stationId = String.valueOf(station.getId());
// 查询站点下的所有充电枪
List<ConnectorInfoVO> connectorList = pileConnectorInfoService.getUniAppConnectorList(Long.parseLong(stationId));
// 统计各状态数量并计算时长
int totalNum = connectorList.size();
int chargingNum = 0; // 充电中
int freeNum = 0; // 空闲
int occupiedNum = 0; // 占用(未充电)
int hangingNum = 0; // 挂起(预约锁定)
int offlineNum = 0; // 离线
int faultNum = 0; // 故障
String now = DateUtils.getDateTime();
for (ConnectorInfoVO connector : connectorList) {
String status = connector.getConnectorStatus();
String pileConnectorCode = connector.getPileConnectorCode();
// 计算时长
if (StringUtils.equals(PileConnectorDataBaseStatusEnum.OCCUPIED_CHARGING.getValue(), status)) {
// 充电中:从实时数据中获取剩余时间
chargingNum++;
OrderBasicInfo order = orderBasicInfoService.queryChargingByPileConnectorCode(pileConnectorCode);
if (order != null) {
List<RealTimeMonitorData> chargingRealTimeData = orderBasicInfoService.getChargingRealTimeData(order.getTransactionCode());
if (CollectionUtils.isNotEmpty(chargingRealTimeData)) {
RealTimeMonitorData realTimeMonitorData = chargingRealTimeData.get(0);
connector.setTimeRemaining(realTimeMonitorData.getTimeRemaining()); // 剩余时长(分钟)
}
}
} else if (StringUtils.equals(PileConnectorDataBaseStatusEnum.FAULT.getValue(), status)) {
// 故障从Redis中获取状态变更时间戳计算从状态变更到现在的时间
faultNum++;
String statusChangeTimeKey = CacheConstants.PILE_CONNECTOR_STATUS_CHANGE_TIME + pileConnectorCode;
String statusChangeTimeStr = redisCache.getCacheObject(statusChangeTimeKey);
if (StringUtils.isNotBlank(statusChangeTimeStr)) {
try {
long duration = DateUtils.intervalTime(statusChangeTimeStr, now);
connector.setDuration(String.valueOf(duration));
} catch (Exception e) {
log.warn("计算状态持续时长失败, pileConnectorCode:{}, statusChangeTimeStr:{}", pileConnectorCode, statusChangeTimeStr, e);
}
}
} else if (StringUtils.equals(PileConnectorDataBaseStatusEnum.OFF_NETWORK.getValue(), status)) {
// 离线从Redis中获取状态变更时间戳计算从状态变更到现在的时间
offlineNum++;
String statusChangeTimeKey = CacheConstants.PILE_CONNECTOR_STATUS_CHANGE_TIME + pileConnectorCode;
String statusChangeTimeStr = redisCache.getCacheObject(statusChangeTimeKey);
if (StringUtils.isNotBlank(statusChangeTimeStr)) {
try {
long duration = DateUtils.intervalTime(statusChangeTimeStr, now);
connector.setDuration(String.valueOf(duration));
} catch (Exception e) {
log.warn("计算状态持续时长失败, pileConnectorCode:{}, statusChangeTimeStr:{}", pileConnectorCode, statusChangeTimeStr, e);
}
}
} else if (StringUtils.equals(PileConnectorDataBaseStatusEnum.OCCUPIED_NOT_CHARGED.getValue(), status)) {
// 占用未充电从Redis中获取状态变更时间戳计算从状态变更到现在的时间
occupiedNum++;
String statusChangeTimeKey = CacheConstants.PILE_CONNECTOR_STATUS_CHANGE_TIME + pileConnectorCode;
String statusChangeTimeStr = redisCache.getCacheObject(statusChangeTimeKey);
if (StringUtils.isNotBlank(statusChangeTimeStr)) {
try {
long duration = DateUtils.intervalTime(statusChangeTimeStr, now);
connector.setDuration(String.valueOf(duration));
} catch (Exception e) {
log.warn("计算状态持续时长失败, pileConnectorCode:{}, statusChangeTimeStr:{}", pileConnectorCode, statusChangeTimeStr, e);
}
}
} else if (StringUtils.equals(PileConnectorDataBaseStatusEnum.OCCUPIED_RESERVED_LOCK.getValue(), status)) {
// 挂起预约锁定从Redis中获取状态变更时间戳计算从状态变更到现在的时间
hangingNum++;
String statusChangeTimeKey = CacheConstants.PILE_CONNECTOR_STATUS_CHANGE_TIME + pileConnectorCode;
String statusChangeTimeStr = redisCache.getCacheObject(statusChangeTimeKey);
if (StringUtils.isNotBlank(statusChangeTimeStr)) {
try {
long duration = DateUtils.intervalTime(statusChangeTimeStr, now);
connector.setDuration(String.valueOf(duration));
} catch (Exception e) {
log.warn("计算状态持续时长失败, pileConnectorCode:{}, statusChangeTimeStr:{}", pileConnectorCode, statusChangeTimeStr, e);
}
}
} else if (StringUtils.equals(PileConnectorDataBaseStatusEnum.FREE.getValue(), status)) {
freeNum++;
}
}
StationWithConnectorStatusVO vo = StationWithConnectorStatusVO.builder()
.stationId(stationId)
.stationName(station.getStationName())
.connectorNum(totalNum)
.chargingConnectorNum(chargingNum)
.freeConnectorNum(freeNum)
.occupiedConnectorNum(occupiedNum)
.hangingConnectorNum(hangingNum)
.offlineConnectorNum(offlineNum)
.faultConnectorNum(faultNum)
.connectorList(connectorList)
.build();
resultList.add(vo);
}
// 构建分页响应
PageInfo<StationWithConnectorStatusVO> pageInfo = new PageInfo<>(resultList);
return PageResponse.builder()
.pageNum(pageNum)
.pageSize(pageSize)
.total(pageInfo.getTotal())
.pages(pageInfo.getPages())
.list(resultList)
.build();
}
}

View File

@@ -66,4 +66,18 @@ public class ConnectorInfoVO {
*/
private String ratedVoltage;
/**
* 状态更新时间(用于计算时长)
*/
private String updateTime;
/**
* 剩余时长(充电中状态,单位:分钟)
*/
private String timeRemaining;
/**
* 状态持续时长(故障/离线/占用/挂起状态,单位:分钟)
*/
private String duration;
}

View File

@@ -0,0 +1,72 @@
package com.jsowell.pile.vo.uniapp.business;
import com.jsowell.pile.vo.base.ConnectorInfoVO;
import lombok.AllArgsConstructor;
import lombok.Builder;
import lombok.Data;
import lombok.NoArgsConstructor;
import java.util.List;
/**
* 运营端小程序站点及充电枪状态VO
*
* @author Auto
* @Date 2024/12/19
*/
@Data
@AllArgsConstructor
@NoArgsConstructor
@Builder
public class StationWithConnectorStatusVO {
/**
* 站点id
*/
private String stationId;
/**
* 站点名称
*/
private String stationName;
/**
* 总枪口数量
*/
private Integer connectorNum;
/**
* 充电中枪口数量
*/
private Integer chargingConnectorNum;
/**
* 空闲枪口数量
*/
private Integer freeConnectorNum;
/**
* 挂起枪口数量
*/
private Integer hangingConnectorNum;
/**
* 占用中枪口数量
*/
private Integer occupiedConnectorNum;
/**
* 离线枪口数量
*/
private Integer offlineConnectorNum;
/**
* 故障枪口数量
*/
private Integer faultConnectorNum;
/**
* 充电枪列表
*/
private List<ConnectorInfoVO> connectorList;
}