新增 查询效率分析接口

This commit is contained in:
Lemon
2026-05-11 13:40:29 +08:00
parent 71a175a0fd
commit 206b53ece0
5 changed files with 380 additions and 0 deletions

View File

@@ -12,10 +12,12 @@ import com.jsowell.pile.dto.business.BusinessEfficiencyQueryDTO;
import com.jsowell.pile.dto.business.BusinessOperationAnalysisQueryDTO; import com.jsowell.pile.dto.business.BusinessOperationAnalysisQueryDTO;
import com.jsowell.pile.dto.business.BusinessScaleQueryDTO; import com.jsowell.pile.dto.business.BusinessScaleQueryDTO;
import com.jsowell.pile.service.BusinessFinancialService; import com.jsowell.pile.service.BusinessFinancialService;
import com.jsowell.pile.vo.uniapp.business.BusinessEfficiencyAnalysisVO;
import com.jsowell.pile.vo.uniapp.business.BusinessEfficiencyVO; import com.jsowell.pile.vo.uniapp.business.BusinessEfficiencyVO;
import com.jsowell.pile.vo.uniapp.business.BusinessGunEfficiencyAnalysisVO; import com.jsowell.pile.vo.uniapp.business.BusinessGunEfficiencyAnalysisVO;
import com.jsowell.pile.vo.uniapp.business.BusinessOperationAnalysisVO; import com.jsowell.pile.vo.uniapp.business.BusinessOperationAnalysisVO;
import com.jsowell.pile.vo.uniapp.business.BusinessScaleVO; import com.jsowell.pile.vo.uniapp.business.BusinessScaleVO;
import com.jsowell.pile.vo.uniapp.business.BusinessStationRankVO;
import com.jsowell.pile.vo.web.MerchantOrderReportVO; import com.jsowell.pile.vo.web.MerchantOrderReportVO;
import org.apache.commons.lang3.StringUtils; import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.annotation.Autowired;
@@ -24,6 +26,8 @@ import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController; import org.springframework.web.bind.annotation.RestController;
import java.util.List;
/** /**
* 运营端财务信息相关Controller * 运营端财务信息相关Controller
* *
@@ -178,4 +182,60 @@ public class BusinessFinancialController extends BaseController {
} }
return response; return response;
} }
/**
* 查询效率分析(单均效率 + 枪均效率)
*
* @param dto 查询参数
* @return 效率分析数据(含单均效率和枪均效率两个维度)
*/
@PostMapping("/efficiencyAnalysis")
public RestApiResponse<?> getEfficiencyAnalysis(@RequestBody BusinessOperationAnalysisQueryDTO dto) {
logger.info("查询效率分析 params:{}", JSONObject.toJSONString(dto));
RestApiResponse<?> response;
try {
if (dto == null) {
throw new BusinessException(ReturnCodeEnum.CODE_PARAM_NOT_NULL_ERROR);
}
BusinessEfficiencyAnalysisVO result = businessFinancialService.getEfficiencyAnalysis(dto);
response = new RestApiResponse<>(result);
logger.info("查询效率分析成功 startTime:{}, endTime:{}",
dto.getStartTime(), dto.getEndTime());
} catch (BusinessException e) {
logger.warn("查询效率分析业务异常 code:{}, message:{}", e.getCode(), e.getMessage(), e);
response = new RestApiResponse<>(e.getCode(), e.getMessage());
} catch (Exception e) {
logger.error("查询效率分析系统异常 params:{}", JSONObject.toJSONString(dto), e);
response = new RestApiResponse<>(e);
}
return response;
}
/**
* 查询场站订单排行
*
* @param dto 查询参数
* @return 场站订单排行列表(按订单数量降序)
*/
@PostMapping("/stationOrderRank")
public RestApiResponse<?> getStationOrderRank(@RequestBody BusinessOperationAnalysisQueryDTO dto) {
logger.info("查询场站订单排行 params:{}", JSONObject.toJSONString(dto));
RestApiResponse<?> response;
try {
if (dto == null) {
throw new BusinessException(ReturnCodeEnum.CODE_PARAM_NOT_NULL_ERROR);
}
List<BusinessStationRankVO> result = businessFinancialService.getStationOrderRank(dto);
response = new RestApiResponse<>(result);
logger.info("查询场站订单排行成功 startTime:{}, endTime:{}, 站点数量:{}",
dto.getStartTime(), dto.getEndTime(), result.size());
} catch (BusinessException e) {
logger.warn("查询场站订单排行业务异常 code:{}, message:{}", e.getCode(), e.getMessage(), e);
response = new RestApiResponse<>(e.getCode(), e.getMessage());
} catch (Exception e) {
logger.error("查询场站订单排行系统异常 params:{}", JSONObject.toJSONString(dto), e);
response = new RestApiResponse<>(e);
}
return response;
}
} }

View File

@@ -6,13 +6,17 @@ import com.jsowell.pile.dto.ParkingCouponRecordQueryDTO;
import com.jsowell.pile.dto.business.BusinessOperationAnalysisQueryDTO; import com.jsowell.pile.dto.business.BusinessOperationAnalysisQueryDTO;
import com.jsowell.pile.dto.business.BusinessEfficiencyQueryDTO; import com.jsowell.pile.dto.business.BusinessEfficiencyQueryDTO;
import com.jsowell.pile.dto.business.BusinessScaleQueryDTO; import com.jsowell.pile.dto.business.BusinessScaleQueryDTO;
import com.jsowell.pile.vo.uniapp.business.BusinessEfficiencyAnalysisVO;
import com.jsowell.pile.vo.uniapp.business.BusinessEfficiencyVO; import com.jsowell.pile.vo.uniapp.business.BusinessEfficiencyVO;
import com.jsowell.pile.vo.uniapp.business.BusinessGunEfficiencyAnalysisVO; import com.jsowell.pile.vo.uniapp.business.BusinessGunEfficiencyAnalysisVO;
import com.jsowell.pile.vo.uniapp.business.BusinessOperationAnalysisVO; import com.jsowell.pile.vo.uniapp.business.BusinessOperationAnalysisVO;
import com.jsowell.pile.vo.uniapp.business.BusinessScaleVO; import com.jsowell.pile.vo.uniapp.business.BusinessScaleVO;
import com.jsowell.pile.vo.uniapp.business.BusinessStationRankVO;
import com.jsowell.pile.vo.web.MerchantOrderReportVO; import com.jsowell.pile.vo.web.MerchantOrderReportVO;
import com.jsowell.pile.vo.web.ParkingCouponRecordVO; import com.jsowell.pile.vo.web.ParkingCouponRecordVO;
import java.util.List;
public interface BusinessFinancialService { public interface BusinessFinancialService {
MerchantOrderReportVO getMyWallet(MerchantOrderReportDTO dto); MerchantOrderReportVO getMyWallet(MerchantOrderReportDTO dto);
@@ -55,4 +59,20 @@ public interface BusinessFinancialService {
* @return 经营效率数据(含指标卡片和曲线图) * @return 经营效率数据(含指标卡片和曲线图)
*/ */
BusinessEfficiencyVO getBusinessEfficiency(BusinessEfficiencyQueryDTO dto); BusinessEfficiencyVO getBusinessEfficiency(BusinessEfficiencyQueryDTO dto);
/**
* 查询场站订单排行
*
* @param dto 查询条件
* @return 场站订单排行列表(按订单数量降序)
*/
List<BusinessStationRankVO> getStationOrderRank(BusinessOperationAnalysisQueryDTO dto);
/**
* 查询效率分析(单均效率 + 枪均效率)
*
* @param dto 查询条件
* @return 效率分析数据(含单均效率和枪均效率两个维度)
*/
BusinessEfficiencyAnalysisVO getEfficiencyAnalysis(BusinessOperationAnalysisQueryDTO dto);
} }

View File

@@ -28,6 +28,7 @@ import com.jsowell.pile.service.PileStationInfoService;
import com.jsowell.pile.service.SettleOrderReportService; import com.jsowell.pile.service.SettleOrderReportService;
import com.jsowell.pile.util.UserUtils; import com.jsowell.pile.util.UserUtils;
import com.jsowell.pile.vo.base.ConnectorInfoVO; import com.jsowell.pile.vo.base.ConnectorInfoVO;
import com.jsowell.pile.vo.uniapp.business.BusinessEfficiencyAnalysisVO;
import com.jsowell.pile.vo.uniapp.business.BusinessGunEfficiencyAnalysisVO; import com.jsowell.pile.vo.uniapp.business.BusinessGunEfficiencyAnalysisVO;
import com.jsowell.pile.vo.uniapp.business.BusinessEfficiencyVO; import com.jsowell.pile.vo.uniapp.business.BusinessEfficiencyVO;
import com.jsowell.pile.vo.uniapp.business.BusinessOperationAnalysisVO; import com.jsowell.pile.vo.uniapp.business.BusinessOperationAnalysisVO;
@@ -36,6 +37,7 @@ import com.jsowell.pile.vo.uniapp.business.BusinessOperationMetricVO;
import com.jsowell.pile.vo.uniapp.business.BusinessScaleChartVO; import com.jsowell.pile.vo.uniapp.business.BusinessScaleChartVO;
import com.jsowell.pile.vo.uniapp.business.BusinessScaleMetricVO; import com.jsowell.pile.vo.uniapp.business.BusinessScaleMetricVO;
import com.jsowell.pile.vo.uniapp.business.BusinessScaleVO; import com.jsowell.pile.vo.uniapp.business.BusinessScaleVO;
import com.jsowell.pile.vo.uniapp.business.BusinessStationRankVO;
import com.jsowell.pile.vo.web.MerchantOrderReportVO; import com.jsowell.pile.vo.web.MerchantOrderReportVO;
import com.jsowell.pile.vo.web.ParkingCouponRecordVO; import com.jsowell.pile.vo.web.ParkingCouponRecordVO;
import lombok.extern.slf4j.Slf4j; import lombok.extern.slf4j.Slf4j;
@@ -795,6 +797,182 @@ public class BusinessFinancialServiceImpl implements BusinessFinancialService {
} }
} }
/**
* 查询效率分析(单均效率 + 枪均效率)
* 单均效率:按订单维度计算平均指标
* 枪均效率:按枪口×天数维度计算日均指标
*
* @param dto 查询条件
* @return 效率分析数据
*/
@Override
public BusinessEfficiencyAnalysisVO getEfficiencyAnalysis(BusinessOperationAnalysisQueryDTO dto) {
if (dto == null) {
return null;
}
if (StringUtils.isBlank(dto.getStartTime()) && StringUtils.isBlank(dto.getEndTime())) {
LocalDate endDate = LocalDate.now();
LocalDate startDate = endDate.minusDays(6);
dto.setStartTime(startDate.toString());
dto.setEndTime(endDate.toString());
}
List<String> stationIdList = resolveStationIds(dto.getStationIdList());
// 并行查询订单汇总和枪口数量
CompletableFuture<BusinessOperationSummaryDTO> summaryFuture = CompletableFuture.supplyAsync(
() -> buildSummaryFromReports(
queryRawReports(stationIdList, dto.getStartTime(), dto.getEndTime())),
FINANCIAL_THREAD_POOL);
CompletableFuture<Integer> connectorCountFuture = CompletableFuture.supplyAsync(
() -> countConnectors(stationIdList), FINANCIAL_THREAD_POOL);
BusinessOperationSummaryDTO summary = summaryFuture.join();
int connectorCount = connectorCountFuture.join();
long dayCount = calculateInclusiveDays(dto.getStartTime(), dto.getEndTime());
// ===== 单均效率指标 =====
// 单均服务费 = 服务费总额 / 订单数量
BigDecimal avgServiceFeePerOrder = BigDecimalUtils.safeDivide(
summary.getServiceAmount(), summary.getOrderCount(), 2);
// 单均充电量 = 充电电量总量 / 订单数量
BigDecimal avgElectricityPerOrder = BigDecimalUtils.safeDivide(
summary.getUseElectricity(), summary.getOrderCount(), 4);
// 单均充电时长 = 总充电时长 / 订单数量
BigDecimal avgChargeTimeMinutesPerOrder = BigDecimalUtils.safeDivide(
summary.getChargeTime(), summary.getOrderCount(), 2);
String avgChargeTimePerOrder = formatMinutesOnly(avgChargeTimeMinutesPerOrder);
// ===== 枪均效率指标 =====
BigDecimal connectorCountBd = BigDecimal.valueOf(connectorCount);
BigDecimal dayCountBd = BigDecimal.valueOf(dayCount);
BigDecimal connectorDayCount = connectorCountBd.multiply(dayCountBd);
// 枪日均服务费 = 服务费总额 / (枪口数量 × 天数)
BigDecimal gunDailyAvgServiceFee = BigDecimalUtils.safeDivide(
summary.getServiceAmount(), connectorDayCount, 2);
// 枪日均充电量 = 充电电量总量 / (枪口数量 × 天数)
BigDecimal gunDailyAvgElectricity = BigDecimalUtils.safeDivide(
summary.getUseElectricity(), connectorDayCount, 4);
// 枪日均充电时长 = 总充电时长 / (枪口数量 × 天数)
BigDecimal gunDailyAvgChargeTimeMinutes = BigDecimalUtils.safeDivide(
summary.getChargeTime(), connectorDayCount, 2);
String gunDailyAvgChargeTime = formatMinutesToHourMinute(gunDailyAvgChargeTimeMinutes);
// ===== 共用指标 =====
// 度均服务费 = 服务费总额 / 充电电量总量
BigDecimal avgServiceFeePerDegree = BigDecimalUtils.safeDivide(
summary.getServiceAmount(), summary.getUseElectricity(), 4);
// 平均功率 = 充电电量总量 × 60 / 总充电时长(分钟)
BigDecimal avgPower = BigDecimalUtils.safeDivide(
summary.getUseElectricity().multiply(new BigDecimal("60")),
summary.getChargeTime(),
4);
return BusinessEfficiencyAnalysisVO.builder()
.startTime(dto.getStartTime())
.endTime(dto.getEndTime())
.avgServiceFeePerOrder(BigDecimalUtils.normalize(avgServiceFeePerOrder))
.avgElectricityPerOrder(BigDecimalUtils.normalize(avgElectricityPerOrder))
.avgChargeTimePerOrder(avgChargeTimePerOrder)
.gunDailyAvgServiceFee(BigDecimalUtils.normalize(gunDailyAvgServiceFee))
.gunDailyAvgElectricity(BigDecimalUtils.normalize(gunDailyAvgElectricity))
.gunDailyAvgChargeTime(gunDailyAvgChargeTime)
.avgServiceFeePerDegree(BigDecimalUtils.normalize(avgServiceFeePerDegree))
.avgPower(BigDecimalUtils.normalize(avgPower))
.build();
}
/**
* 将分钟数格式化为xxm格式用于单均充电时长
*
* @param minutes 分钟数
* @return 格式化结果
*/
private String formatMinutesOnly(BigDecimal minutes) {
long totalMinutes = BigDecimalUtils.nullToZero(minutes)
.setScale(0, RoundingMode.HALF_UP)
.longValue();
return totalMinutes + "m";
}
/**
* 查询场站订单排行
* 按站点分组统计订单数量,按订单数量降序排列
*
* @param dto 查询条件
* @return 场站订单排行列表
*/
@Override
public List<BusinessStationRankVO> getStationOrderRank(BusinessOperationAnalysisQueryDTO dto) {
if (dto == null) {
return new ArrayList<>();
}
if (StringUtils.isBlank(dto.getStartTime()) && StringUtils.isBlank(dto.getEndTime())) {
LocalDate endDate = LocalDate.now();
LocalDate startDate = endDate.minusDays(6);
dto.setStartTime(startDate.toString());
dto.setEndTime(endDate.toString());
}
List<String> stationIdList = resolveStationIds(dto.getStationIdList());
// 查询结算报表原始数据
List<SettleOrderReport> reportList = queryRawReports(
stationIdList, dto.getStartTime(), dto.getEndTime());
if (CollectionUtils.isEmpty(reportList)) {
return new ArrayList<>();
}
// 按站点ID分组累加订单数量
Map<String, Integer> stationOrderCountMap = new LinkedHashMap<>();
for (SettleOrderReport report : reportList) {
String sId = report.getStationId();
if (StringUtils.isBlank(sId)) {
continue;
}
int chargeNum = BigDecimalUtils.parseOrZero(report.getChargeNum()).intValue();
stationOrderCountMap.merge(sId, chargeNum, Integer::sum);
}
// 批量查询站点名称
Map<String, String> stationNameMap = new LinkedHashMap<>();
for (String sId : stationOrderCountMap.keySet()) {
try {
PileStationInfo stationInfo = pileStationInfoService.selectPileStationInfoById(Long.valueOf(sId));
if (stationInfo != null) {
stationNameMap.put(sId, stationInfo.getStationName());
} else {
stationNameMap.put(sId, "未知站点");
}
} catch (Exception e) {
log.warn("查询站点名称失败 stationId:{}", sId, e);
stationNameMap.put(sId, "未知站点");
}
}
// 按订单数量降序排列并构建排行列表
List<BusinessStationRankVO> rankList = stationOrderCountMap.entrySet().stream()
.map(entry -> BusinessStationRankVO.builder()
.stationId(entry.getKey())
.stationName(stationNameMap.getOrDefault(entry.getKey(), "未知站点"))
.orderCount(entry.getValue())
.build())
.sorted((a, b) -> Integer.compare(
b.getOrderCount() != null ? b.getOrderCount() : 0,
a.getOrderCount() != null ? a.getOrderCount() : 0))
.collect(Collectors.toList());
// 设置排行名次
for (int i = 0; i < rankList.size(); i++) {
rankList.get(i).setRank(i + 1);
}
return rankList;
}
/** /**
* 查询经营效率 * 查询经营效率
* 优化:当前周期和上周期汇总并行查询,枪口数量与总额定功率并行查询 * 优化:当前周期和上周期汇总并行查询,枪口数量与总额定功率并行查询

View File

@@ -0,0 +1,84 @@
package com.jsowell.pile.vo.uniapp.business;
import lombok.AllArgsConstructor;
import lombok.Builder;
import lombok.Data;
import lombok.NoArgsConstructor;
import java.math.BigDecimal;
/**
* 效率分析VO包含单均效率和枪均效率两个维度的数据
*
* @author Lemon
*/
@Data
@AllArgsConstructor
@NoArgsConstructor
@Builder
public class BusinessEfficiencyAnalysisVO {
/**
* 开始时间
*/
private String startTime;
/**
* 结束时间
*/
private String endTime;
// ========== 单均效率指标 ==========
/**
* 单均服务费(元)
* = 服务费总额 / 订单数量
*/
private BigDecimal avgServiceFeePerOrder;
/**
* 单均充电量(度)
* = 充电电量总量 / 订单数量
*/
private BigDecimal avgElectricityPerOrder;
/**
* 单均充电时长格式xxm
* = 总充电时长(分钟) / 订单数量
*/
private String avgChargeTimePerOrder;
// ========== 枪均效率指标 ==========
/**
* 枪日均服务费(元)
* = 服务费总额 / (枪口数量 × 天数)
*/
private BigDecimal gunDailyAvgServiceFee;
/**
* 枪日均充电量(度)
* = 充电电量总量 / (枪口数量 × 天数)
*/
private BigDecimal gunDailyAvgElectricity;
/**
* 枪日均充电时长格式xxhxxm
* = 总充电时长(分钟) / (枪口数量 × 天数)
*/
private String gunDailyAvgChargeTime;
// ========== 共用指标 ==========
/**
* 度均服务费(元)
* = 服务费总额 / 充电电量总量
*/
private BigDecimal avgServiceFeePerDegree;
/**
* 平均功率(KW)
* = 充电电量总量 × 60 / 总充电时长(分钟)
*/
private BigDecimal avgPower;
}

View File

@@ -0,0 +1,38 @@
package com.jsowell.pile.vo.uniapp.business;
import lombok.AllArgsConstructor;
import lombok.Builder;
import lombok.Data;
import lombok.NoArgsConstructor;
/**
* 场站排行VO
*
* @author zhangziao
*/
@Data
@AllArgsConstructor
@NoArgsConstructor
@Builder
public class BusinessStationRankVO {
/**
* 排行名次
*/
private Integer rank;
/**
* 站点ID
*/
private String stationId;
/**
* 场站名称
*/
private String stationName;
/**
* 订单总数
*/
private Integer orderCount;
}