From 51ec0edaa4acc013088974134a9ef2cf1bfcbd38 Mon Sep 17 00:00:00 2001 From: Lemon Date: Tue, 21 Apr 2026 09:13:04 +0800 Subject: [PATCH 1/5] =?UTF-8?q?=E6=96=B0=E5=A2=9E=20=E6=9F=A5=E8=AF=A2?= =?UTF-8?q?=E7=BB=8F=E8=90=A5=E6=95=88=E7=8E=87=E6=8E=A5=E5=8F=A3?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../business/BusinessFinancialController.java | 30 ++ jsowell-admin/src/main/resources/logback.xml | 2 +- .../service/BusinessFinancialService.java | 10 + .../impl/BusinessFinancialServiceImpl.java | 328 ++++++++++++++++++ .../impl/OrderBasicInfoServiceImpl.java | 2 +- 5 files changed, 370 insertions(+), 2 deletions(-) diff --git a/jsowell-admin/src/main/java/com/jsowell/api/uniapp/business/BusinessFinancialController.java b/jsowell-admin/src/main/java/com/jsowell/api/uniapp/business/BusinessFinancialController.java index f80ae21e1..d0ae8ebb4 100644 --- a/jsowell-admin/src/main/java/com/jsowell/api/uniapp/business/BusinessFinancialController.java +++ b/jsowell-admin/src/main/java/com/jsowell/api/uniapp/business/BusinessFinancialController.java @@ -8,9 +8,11 @@ import com.jsowell.common.exception.BusinessException; import com.jsowell.common.response.RestApiResponse; import com.jsowell.pile.dto.MerchantOrderReportDTO; import com.jsowell.pile.dto.ParkingCouponRecordQueryDTO; +import com.jsowell.pile.dto.business.BusinessEfficiencyQueryDTO; import com.jsowell.pile.dto.business.BusinessOperationAnalysisQueryDTO; import com.jsowell.pile.dto.business.BusinessScaleQueryDTO; import com.jsowell.pile.service.BusinessFinancialService; +import com.jsowell.pile.vo.uniapp.business.BusinessEfficiencyVO; import com.jsowell.pile.vo.uniapp.business.BusinessGunEfficiencyAnalysisVO; import com.jsowell.pile.vo.uniapp.business.BusinessOperationAnalysisVO; import com.jsowell.pile.vo.uniapp.business.BusinessScaleVO; @@ -148,4 +150,32 @@ public class BusinessFinancialController extends BaseController { } return response; } + + /** + * 查询经营效率 + * + * @param dto 查询参数 + * @return 经营效率数据(含指标卡片和曲线图) + */ + @PostMapping("/businessEfficiency") + public RestApiResponse getBusinessEfficiency(@RequestBody BusinessEfficiencyQueryDTO dto) { + logger.info("查询经营效率 params:{}", JSONObject.toJSONString(dto)); + RestApiResponse response; + try { + if (dto == null) { + throw new BusinessException(ReturnCodeEnum.CODE_PARAM_NOT_NULL_ERROR); + } + BusinessEfficiencyVO result = businessFinancialService.getBusinessEfficiency(dto); + response = new RestApiResponse<>(result); + logger.info("查询经营效率成功 startTime:{}, endTime:{}, selectedMetricCode:{}", + dto.getStartTime(), dto.getEndTime(), dto.getSelectedMetricCode()); + } 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; + } } diff --git a/jsowell-admin/src/main/resources/logback.xml b/jsowell-admin/src/main/resources/logback.xml index d293b86f2..b3591c688 100644 --- a/jsowell-admin/src/main/resources/logback.xml +++ b/jsowell-admin/src/main/resources/logback.xml @@ -1,7 +1,7 @@ - + diff --git a/jsowell-pile/src/main/java/com/jsowell/pile/service/BusinessFinancialService.java b/jsowell-pile/src/main/java/com/jsowell/pile/service/BusinessFinancialService.java index ea94965fc..ce5dfb16d 100644 --- a/jsowell-pile/src/main/java/com/jsowell/pile/service/BusinessFinancialService.java +++ b/jsowell-pile/src/main/java/com/jsowell/pile/service/BusinessFinancialService.java @@ -4,7 +4,9 @@ import com.jsowell.common.core.page.PageResponse; import com.jsowell.pile.dto.MerchantOrderReportDTO; import com.jsowell.pile.dto.ParkingCouponRecordQueryDTO; import com.jsowell.pile.dto.business.BusinessOperationAnalysisQueryDTO; +import com.jsowell.pile.dto.business.BusinessEfficiencyQueryDTO; import com.jsowell.pile.dto.business.BusinessScaleQueryDTO; +import com.jsowell.pile.vo.uniapp.business.BusinessEfficiencyVO; import com.jsowell.pile.vo.uniapp.business.BusinessGunEfficiencyAnalysisVO; import com.jsowell.pile.vo.uniapp.business.BusinessOperationAnalysisVO; import com.jsowell.pile.vo.uniapp.business.BusinessScaleVO; @@ -45,4 +47,12 @@ public interface BusinessFinancialService { * @return 经营规模数据(含指标卡片和曲线图) */ BusinessScaleVO getBusinessScale(BusinessScaleQueryDTO dto); + + /** + * 查询经营效率 + * + * @param dto 查询条件 + * @return 经营效率数据(含指标卡片和曲线图) + */ + BusinessEfficiencyVO getBusinessEfficiency(BusinessEfficiencyQueryDTO dto); } diff --git a/jsowell-pile/src/main/java/com/jsowell/pile/service/impl/BusinessFinancialServiceImpl.java b/jsowell-pile/src/main/java/com/jsowell/pile/service/impl/BusinessFinancialServiceImpl.java index 8cbe41293..cd1b2c2d8 100644 --- a/jsowell-pile/src/main/java/com/jsowell/pile/service/impl/BusinessFinancialServiceImpl.java +++ b/jsowell-pile/src/main/java/com/jsowell/pile/service/impl/BusinessFinancialServiceImpl.java @@ -12,11 +12,13 @@ import com.jsowell.common.enums.ykc.ReturnCodeEnum; import com.jsowell.common.exception.BusinessException; import com.jsowell.pile.dto.MerchantOrderReportDTO; import com.jsowell.pile.dto.ParkingCouponRecordQueryDTO; +import com.jsowell.pile.dto.business.BusinessEfficiencyQueryDTO; import com.jsowell.pile.dto.business.BusinessOperationAnalysisQueryDTO; import com.jsowell.pile.dto.business.BusinessOperationDateRangeDTO; import com.jsowell.pile.dto.business.BusinessOperationSummaryDTO; import com.jsowell.pile.dto.business.BusinessScaleQueryDTO; import com.jsowell.pile.domain.PileConnectorInfo; +import com.jsowell.pile.domain.PileStationInfo; import com.jsowell.pile.domain.SettleOrderReport; import com.jsowell.pile.service.BusinessFinancialService; import com.jsowell.pile.service.CarCouponRecordService; @@ -25,7 +27,9 @@ import com.jsowell.pile.service.PileConnectorInfoService; import com.jsowell.pile.service.PileStationInfoService; import com.jsowell.pile.service.SettleOrderReportService; import com.jsowell.pile.util.UserUtils; +import com.jsowell.pile.vo.base.ConnectorInfoVO; import com.jsowell.pile.vo.uniapp.business.BusinessGunEfficiencyAnalysisVO; +import com.jsowell.pile.vo.uniapp.business.BusinessEfficiencyVO; import com.jsowell.pile.vo.uniapp.business.BusinessOperationAnalysisVO; import com.jsowell.pile.vo.uniapp.business.BusinessOperationDiagnosisItemVO; import com.jsowell.pile.vo.uniapp.business.BusinessOperationMetricVO; @@ -74,6 +78,11 @@ public class BusinessFinancialServiceImpl implements BusinessFinancialService { private static final String SCALE_METRIC_SERVICE_AMOUNT = "SERVICE_AMOUNT"; private static final String SCALE_METRIC_USE_ELECTRICITY = "USE_ELECTRICITY"; + private static final String EFFICIENCY_METRIC_AVG_SERVICE_FEE_PER_DEGREE = "AVG_SERVICE_FEE_PER_DEGREE"; + private static final String EFFICIENCY_METRIC_TIME_UTILIZATION = "TIME_UTILIZATION"; + private static final String EFFICIENCY_METRIC_GUN_AVG_ELECTRICITY = "GUN_AVG_ELECTRICITY"; + private static final String EFFICIENCY_METRIC_POWER_UTILIZATION = "POWER_UTILIZATION"; + /** * 财务查询通用线程池(支持多方法并行查询) * 核心线程数4:覆盖经营规模(2路)、我的钱包(3路)、经营分析(2路)、枪均效率(2路)等场景 @@ -785,4 +794,323 @@ public class BusinessFinancialServiceImpl implements BusinessFinancialService { return BigDecimalUtils.nullToZero(report.getUseElectricity()); } } + + /** + * 查询经营效率 + * 优化:当前周期和上周期汇总并行查询,枪口数量与总额定功率并行查询 + * + * @param dto 查询条件 + * @return 经营效率数据 + */ + @Override + public BusinessEfficiencyVO getBusinessEfficiency(BusinessEfficiencyQueryDTO 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()); + } + + BusinessOperationDateRangeDTO range = buildDateRangeFromEfficiency(dto); + List stationIdList = resolveStationIds(dto.getStationIdList()); + + // 并行查询当前周期和上周期原始报表数据 + CompletableFuture> currentReportFuture = CompletableFuture.supplyAsync( + () -> queryRawReports(stationIdList, range.getCurrentStart(), range.getCurrentEnd()), + FINANCIAL_THREAD_POOL); + CompletableFuture> previousReportFuture = CompletableFuture.supplyAsync( + () -> queryRawReports(stationIdList, range.getPreviousStart(), range.getPreviousEnd()), + FINANCIAL_THREAD_POOL); + + // 等待报表查询完成 + List currentReports = currentReportFuture.join(); + List previousReports = previousReportFuture.join(); + + BusinessOperationSummaryDTO currentSummary = buildSummaryFromReports(currentReports); + BusinessOperationSummaryDTO previousSummary = buildSummaryFromReports(previousReports); + + Map currentDailyMap = buildDailyMapFromReports(currentReports); + Map previousDailyMap = buildDailyMapFromReports(previousReports); + + long dayCount = calculateInclusiveDays(range.getCurrentStart(), range.getCurrentEnd()); + + // 查询枪口数量和总额定功率 + ConnectorStats connectorStats = buildConnectorStats(stationIdList); + int connectorCount = connectorStats.getConnectorCount(); + BigDecimal totalRatedPower = connectorStats.getTotalRatedPower(); + + // 构建指标卡片 + BigDecimal currentAvgServiceFeePerDegree = BigDecimalUtils.safeDivide( + currentSummary.getServiceAmount(), currentSummary.getUseElectricity(), 2); + BigDecimal previousAvgServiceFeePerDegree = BigDecimalUtils.safeDivide( + previousSummary.getServiceAmount(), previousSummary.getUseElectricity(), 2); + + BigDecimal currentTimeUtilization = calculateTimeUtilization( + currentSummary.getChargeTime(), connectorCount, dayCount); + BigDecimal previousTimeUtilization = calculateTimeUtilization( + previousSummary.getChargeTime(), connectorCount, dayCount); + + BigDecimal currentGunAvgElectricity = connectorCount > 0 + ? BigDecimalUtils.safeDivide(currentSummary.getUseElectricity(), + BigDecimal.valueOf(connectorCount), 2) + : BigDecimal.ZERO; + BigDecimal previousGunAvgElectricity = connectorCount > 0 + ? BigDecimalUtils.safeDivide(previousSummary.getUseElectricity(), + BigDecimal.valueOf(connectorCount), 2) + : BigDecimal.ZERO; + + BigDecimal currentPowerUtilization = calculatePowerUtilization( + currentSummary.getUseElectricity(), currentSummary.getChargeTime(), + connectorCount, dayCount, totalRatedPower); + BigDecimal previousPowerUtilization = calculatePowerUtilization( + previousSummary.getUseElectricity(), previousSummary.getChargeTime(), + connectorCount, dayCount, totalRatedPower); + + List metricList = new ArrayList<>(); + metricList.add(buildScaleMetric(EFFICIENCY_METRIC_AVG_SERVICE_FEE_PER_DEGREE, "度均服务费", "元", + currentAvgServiceFeePerDegree, previousAvgServiceFeePerDegree)); + metricList.add(buildScaleMetric(EFFICIENCY_METRIC_TIME_UTILIZATION, "时间利用率", "%", + currentTimeUtilization, previousTimeUtilization)); + metricList.add(buildScaleMetric(EFFICIENCY_METRIC_GUN_AVG_ELECTRICITY, "枪均电量", "度", + currentGunAvgElectricity, previousGunAvgElectricity)); + metricList.add(buildScaleMetric(EFFICIENCY_METRIC_POWER_UTILIZATION, "功率利用率", "%", + currentPowerUtilization, previousPowerUtilization)); + + // 构建选中指标的曲线图数据 + String selectedMetricCode = StringUtils.isBlank(dto.getSelectedMetricCode()) + ? EFFICIENCY_METRIC_AVG_SERVICE_FEE_PER_DEGREE : dto.getSelectedMetricCode(); + BusinessScaleChartVO chartData = buildEfficiencyChartFromMaps( + selectedMetricCode, range, currentDailyMap, previousDailyMap, + connectorCount, totalRatedPower); + + return BusinessEfficiencyVO.builder() + .currentStartTime(range.getCurrentStart()) + .currentEndTime(range.getCurrentEnd()) + .previousStartTime(range.getPreviousStart()) + .previousEndTime(range.getPreviousEnd()) + .metricList(metricList) + .chartData(chartData) + .build(); + } + + /** + * 构建经营效率日期区间 + */ + private BusinessOperationDateRangeDTO buildDateRangeFromEfficiency(BusinessEfficiencyQueryDTO dto) { + try { + LocalDate currentStart = LocalDate.parse(dto.getStartTime()); + LocalDate currentEnd = LocalDate.parse(dto.getEndTime()); + if (currentEnd.isBefore(currentStart)) { + throw new BusinessException(ReturnCodeEnum.CODE_PARAM_NOT_NULL_ERROR); + } + long days = ChronoUnit.DAYS.between(currentStart, currentEnd) + 1; + LocalDate previousEnd = currentStart.minusDays(1); + LocalDate previousStart = previousEnd.minusDays(days - 1); + return BusinessOperationDateRangeDTO.builder() + .currentStart(currentStart.toString()) + .currentEnd(currentEnd.toString()) + .previousStart(previousStart.toString()) + .previousEnd(previousEnd.toString()) + .build(); + } catch (BusinessException e) { + throw e; + } catch (Exception e) { + throw new BusinessException(ReturnCodeEnum.CODE_PARAM_NOT_NULL_ERROR); + } + } + + /** + * 构建枪口统计信息(枪口数量 + 总额定功率) + */ + private ConnectorStats buildConnectorStats(List stationIdList) { + List connectors; + if (stationIdList == null) { + // 平台账号:先查询所有站点ID,再批量查询枪口信息 + List allStations = pileStationInfoService.selectPileStationInfoList(new PileStationInfo()); + List allStationIds = allStations.stream() + .map(s -> String.valueOf(s.getId())) + .collect(Collectors.toList()); + if (allStationIds.isEmpty()) { + return new ConnectorStats(0, BigDecimal.ZERO); + } + connectors = pileConnectorInfoService.batchSelectConnectorList(allStationIds); + } else if (stationIdList.isEmpty()) { + return new ConnectorStats(0, BigDecimal.ZERO); + } else { + connectors = pileConnectorInfoService.batchSelectConnectorList(stationIdList); + } + + if (CollectionUtils.isEmpty(connectors)) { + return new ConnectorStats(0, BigDecimal.ZERO); + } + + BigDecimal totalRatedPower = BigDecimal.ZERO; + for (ConnectorInfoVO connector : connectors) { + totalRatedPower = totalRatedPower.add(BigDecimalUtils.parseOrZero(connector.getRatedPower())); + } + + return new ConnectorStats(connectors.size(), totalRatedPower); + } + + /** + * 计算时间利用率(%) + * = 总充电时长(分钟) / (枪口数 × 天数 × 1440分钟) × 100 + */ + private BigDecimal calculateTimeUtilization(BigDecimal chargeTime, int connectorCount, long dayCount) { + if (connectorCount == 0 || dayCount == 0) { + return BigDecimal.ZERO; + } + BigDecimal totalAvailableMinutes = BigDecimal.valueOf(connectorCount) + .multiply(BigDecimal.valueOf(dayCount)) + .multiply(new BigDecimal("1440")); + BigDecimal utilization = BigDecimalUtils.safeDivide( + BigDecimalUtils.nullToZero(chargeTime), totalAvailableMinutes, 4); + return utilization.multiply(new BigDecimal("100")).setScale(2, RoundingMode.HALF_UP); + } + + /** + * 计算功率利用率(%) + * = 实际总能量 / 理论最大总能量 × 100 + * = useElectricity / (总额定功率 × 天数 × 24) × 100 + */ + private BigDecimal calculatePowerUtilization(BigDecimal useElectricity, BigDecimal chargeTime, + int connectorCount, long dayCount, BigDecimal totalRatedPower) { + if (totalRatedPower.compareTo(BigDecimal.ZERO) == 0 || dayCount == 0) { + return BigDecimal.ZERO; + } + BigDecimal theoreticalMaxEnergy = totalRatedPower + .multiply(BigDecimal.valueOf(dayCount)) + .multiply(new BigDecimal("24")); + BigDecimal utilization = BigDecimalUtils.safeDivide( + BigDecimalUtils.nullToZero(useElectricity), theoreticalMaxEnergy, 4); + return utilization.multiply(new BigDecimal("100")).setScale(2, RoundingMode.HALF_UP); + } + + /** + * 从dailyMap构建经营效率曲线图数据 + * 每个指标按天计算(度均服务费=当天服务费/当天电量, 时间利用率=当天充电时长/可用时长, 等) + */ + private BusinessScaleChartVO buildEfficiencyChartFromMaps(String metricCode, + BusinessOperationDateRangeDTO range, + Map currentDailyMap, + Map previousDailyMap, + int connectorCount, + BigDecimal totalRatedPower) { + String metricName; + String unit; + switch (metricCode) { + case EFFICIENCY_METRIC_TIME_UTILIZATION: + metricName = "时间利用率"; + unit = "%"; + break; + case EFFICIENCY_METRIC_GUN_AVG_ELECTRICITY: + metricName = "枪均电量"; + unit = "度"; + break; + case EFFICIENCY_METRIC_POWER_UTILIZATION: + metricName = "功率利用率"; + unit = "%"; + break; + default: + metricName = "度均服务费"; + unit = "元"; + break; + } + + LocalDate currentStart = LocalDate.parse(range.getCurrentStart()); + LocalDate currentEnd = LocalDate.parse(range.getCurrentEnd()); + LocalDate previousStart = LocalDate.parse(range.getPreviousStart()); + + long dayCount = ChronoUnit.DAYS.between(currentStart, currentEnd) + 1; + DateTimeFormatter displayFormatter = DateTimeFormatter.ofPattern("MM/dd"); + + List chartPoints = new ArrayList<>(); + for (long i = 0; i < dayCount; i++) { + LocalDate currentDate = currentStart.plusDays(i); + LocalDate previousDate = previousStart.plusDays(i); + + SettleOrderReport currentReport = currentDailyMap.get(currentDate.toString()); + SettleOrderReport previousReport = previousDailyMap.get(previousDate.toString()); + + BigDecimal currentValue = calculateEfficiencyMetricValue( + metricCode, currentReport, connectorCount, 1, totalRatedPower); + BigDecimal previousValue = calculateEfficiencyMetricValue( + metricCode, previousReport, connectorCount, 1, totalRatedPower); + + chartPoints.add(BusinessScaleChartVO.ChartPoint.builder() + .date(currentDate.format(displayFormatter)) + .fullDate(currentDate.toString()) + .value(BigDecimalUtils.normalize(currentValue)) + .previousValue(BigDecimalUtils.normalize(previousValue)) + .changeRate(BigDecimalUtils.calculateRate( + BigDecimalUtils.nullToZero(currentValue), + BigDecimalUtils.nullToZero(previousValue))) + .build()); + } + + return BusinessScaleChartVO.builder() + .metricCode(metricCode) + .metricName(metricName) + .unit(unit) + .chartData(chartPoints) + .build(); + } + + /** + * 根据指标编码计算单条报表记录对应的经营效率指标值 + */ + private BigDecimal calculateEfficiencyMetricValue(String metricCode, SettleOrderReport report, + int connectorCount, long dayCount, + BigDecimal totalRatedPower) { + if (report == null) { + return BigDecimal.ZERO; + } + BigDecimal serviceAmount = BigDecimalUtils.nullToZero(report.getServiceAmount()); + BigDecimal useElectricity = BigDecimalUtils.nullToZero(report.getUseElectricity()); + BigDecimal chargeTime = BigDecimalUtils.parseOrZero(report.getChargeTime()); + + switch (metricCode) { + case EFFICIENCY_METRIC_AVG_SERVICE_FEE_PER_DEGREE: + // 度均服务费 = 服务费 / 用电量 + return BigDecimalUtils.safeDivide(serviceAmount, useElectricity, 2); + case EFFICIENCY_METRIC_TIME_UTILIZATION: + // 时间利用率 = 充电时长 / (枪口数 × 1天 × 1440) × 100 + return calculateTimeUtilization(chargeTime, connectorCount, dayCount); + case EFFICIENCY_METRIC_GUN_AVG_ELECTRICITY: + // 枪均电量 = 用电量 / 枪口数 + return connectorCount > 0 + ? BigDecimalUtils.safeDivide(useElectricity, BigDecimal.valueOf(connectorCount), 2) + : BigDecimal.ZERO; + case EFFICIENCY_METRIC_POWER_UTILIZATION: + // 功率利用率 = 用电量 / (总额定功率 × 1天 × 24) × 100 + return calculatePowerUtilization(useElectricity, chargeTime, + connectorCount, dayCount, totalRatedPower); + default: + return BigDecimal.ZERO; + } + } + + /** + * 枪口统计信息内部类 + */ + private static class ConnectorStats { + private final int connectorCount; + private final BigDecimal totalRatedPower; + + ConnectorStats(int connectorCount, BigDecimal totalRatedPower) { + this.connectorCount = connectorCount; + this.totalRatedPower = totalRatedPower; + } + + int getConnectorCount() { + return connectorCount; + } + + BigDecimal getTotalRatedPower() { + return totalRatedPower; + } + } } diff --git a/jsowell-pile/src/main/java/com/jsowell/pile/service/impl/OrderBasicInfoServiceImpl.java b/jsowell-pile/src/main/java/com/jsowell/pile/service/impl/OrderBasicInfoServiceImpl.java index de3100f7a..b0f5a2da6 100644 --- a/jsowell-pile/src/main/java/com/jsowell/pile/service/impl/OrderBasicInfoServiceImpl.java +++ b/jsowell-pile/src/main/java/com/jsowell/pile/service/impl/OrderBasicInfoServiceImpl.java @@ -3497,7 +3497,7 @@ public class OrderBasicInfoServiceImpl implements OrderBasicInfoService { logger.debug("redis中没有实时数据了,去数据库查"); // redis中为空,去查库 OrderMonitorData orderMonitorData = orderMonitorDataService.selectByTransactionCode(transactionCode); - if (orderMonitorData != null) { + if (orderMonitorData != null && StringUtils.isNotBlank(orderMonitorData.getMonitorData())) { String monitorData = orderMonitorData.getMonitorData(); List dataList = JSON.parseArray(monitorData, RealTimeMonitorData.class); resultList.addAll(dataList); From ab0533e18db9fe5db2c23f7c25e5ad940030f617 Mon Sep 17 00:00:00 2001 From: Lemon Date: Tue, 21 Apr 2026 10:37:18 +0800 Subject: [PATCH 2/5] =?UTF-8?q?=E6=96=B0=E5=A2=9E=20=E6=9F=A5=E8=AF=A2?= =?UTF-8?q?=E7=BB=8F=E8=90=A5=E6=95=88=E7=8E=87=E6=8E=A5=E5=8F=A3=E7=9B=B8?= =?UTF-8?q?=E5=85=B3=E5=AE=9E=E4=BD=93=E7=B1=BB?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../business/BusinessEfficiencyQueryDTO.java | 43 ++++++++++++++++ .../uniapp/business/BusinessEfficiencyVO.java | 51 +++++++++++++++++++ 2 files changed, 94 insertions(+) create mode 100644 jsowell-pile/src/main/java/com/jsowell/pile/dto/business/BusinessEfficiencyQueryDTO.java create mode 100644 jsowell-pile/src/main/java/com/jsowell/pile/vo/uniapp/business/BusinessEfficiencyVO.java diff --git a/jsowell-pile/src/main/java/com/jsowell/pile/dto/business/BusinessEfficiencyQueryDTO.java b/jsowell-pile/src/main/java/com/jsowell/pile/dto/business/BusinessEfficiencyQueryDTO.java new file mode 100644 index 000000000..111e68871 --- /dev/null +++ b/jsowell-pile/src/main/java/com/jsowell/pile/dto/business/BusinessEfficiencyQueryDTO.java @@ -0,0 +1,43 @@ +package com.jsowell.pile.dto.business; + +import lombok.AllArgsConstructor; +import lombok.Builder; +import lombok.Data; +import lombok.NoArgsConstructor; + +import java.util.List; + +/** + * 经营效率查询DTO + * + * @author zhangziao + * @date 2026/4/16 + */ +@Data +@AllArgsConstructor +@NoArgsConstructor +@Builder +public class BusinessEfficiencyQueryDTO { + + /** + * 开始时间,格式:yyyy-MM-dd + */ + private String startTime; + + /** + * 结束时间,格式:yyyy-MM-dd + */ + private String endTime; + + /** + * 站点id列表 + */ + private List stationIdList; + + /** + * 当前选中的指标编码,用于查询对应的曲线图数据 + * AVG_SERVICE_FEE_PER_DEGREE-度均服务费, TIME_UTILIZATION-时间利用率, + * GUN_AVG_ELECTRICITY-枪均电量, POWER_UTILIZATION-功率利用率 + */ + private String selectedMetricCode; +} diff --git a/jsowell-pile/src/main/java/com/jsowell/pile/vo/uniapp/business/BusinessEfficiencyVO.java b/jsowell-pile/src/main/java/com/jsowell/pile/vo/uniapp/business/BusinessEfficiencyVO.java new file mode 100644 index 000000000..038542503 --- /dev/null +++ b/jsowell-pile/src/main/java/com/jsowell/pile/vo/uniapp/business/BusinessEfficiencyVO.java @@ -0,0 +1,51 @@ +package com.jsowell.pile.vo.uniapp.business; + +import lombok.AllArgsConstructor; +import lombok.Builder; +import lombok.Data; +import lombok.NoArgsConstructor; + +import java.util.List; + +/** + * 经营效率VO + * + * @author zhangziao + * @date 2026/4/16 + */ +@Data +@AllArgsConstructor +@NoArgsConstructor +@Builder +public class BusinessEfficiencyVO { + + /** + * 当前周期开始时间 + */ + private String currentStartTime; + + /** + * 当前周期结束时间 + */ + private String currentEndTime; + + /** + * 上周期开始时间 + */ + private String previousStartTime; + + /** + * 上周期结束时间 + */ + private String previousEndTime; + + /** + * 指标卡片列表(度均服务费、时间利用率、枪均电量、功率利用率) + */ + private List metricList; + + /** + * 当前选中指标对应的曲线图数据 + */ + private BusinessScaleChartVO chartData; +} From 0a5fdf0502a0ed9557199715823f780f85f9647a Mon Sep 17 00:00:00 2001 From: Lemon Date: Thu, 30 Apr 2026 09:40:07 +0800 Subject: [PATCH 3/5] update --- .../pile/dto/business/BusinessEfficiencyQueryDTO.java | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/jsowell-pile/src/main/java/com/jsowell/pile/dto/business/BusinessEfficiencyQueryDTO.java b/jsowell-pile/src/main/java/com/jsowell/pile/dto/business/BusinessEfficiencyQueryDTO.java index 111e68871..421098732 100644 --- a/jsowell-pile/src/main/java/com/jsowell/pile/dto/business/BusinessEfficiencyQueryDTO.java +++ b/jsowell-pile/src/main/java/com/jsowell/pile/dto/business/BusinessEfficiencyQueryDTO.java @@ -36,8 +36,10 @@ public class BusinessEfficiencyQueryDTO { /** * 当前选中的指标编码,用于查询对应的曲线图数据 - * AVG_SERVICE_FEE_PER_DEGREE-度均服务费, TIME_UTILIZATION-时间利用率, - * GUN_AVG_ELECTRICITY-枪均电量, POWER_UTILIZATION-功率利用率 + * AVG_SERVICE_FEE_PER_DEGREE-度均服务费, + * TIME_UTILIZATION-时间利用率, + * GUN_AVG_ELECTRICITY-枪均电量, + * POWER_UTILIZATION-功率利用率 */ private String selectedMetricCode; } From 206b53ece041fe2b6846e5cd0cbbeab84da189d7 Mon Sep 17 00:00:00 2001 From: Lemon Date: Mon, 11 May 2026 13:40:29 +0800 Subject: [PATCH 4/5] =?UTF-8?q?=E6=96=B0=E5=A2=9E=20=E6=9F=A5=E8=AF=A2?= =?UTF-8?q?=E6=95=88=E7=8E=87=E5=88=86=E6=9E=90=E6=8E=A5=E5=8F=A3?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../business/BusinessFinancialController.java | 60 ++++++ .../service/BusinessFinancialService.java | 20 ++ .../impl/BusinessFinancialServiceImpl.java | 178 ++++++++++++++++++ .../BusinessEfficiencyAnalysisVO.java | 84 +++++++++ .../business/BusinessStationRankVO.java | 38 ++++ 5 files changed, 380 insertions(+) create mode 100644 jsowell-pile/src/main/java/com/jsowell/pile/vo/uniapp/business/BusinessEfficiencyAnalysisVO.java create mode 100644 jsowell-pile/src/main/java/com/jsowell/pile/vo/uniapp/business/BusinessStationRankVO.java diff --git a/jsowell-admin/src/main/java/com/jsowell/api/uniapp/business/BusinessFinancialController.java b/jsowell-admin/src/main/java/com/jsowell/api/uniapp/business/BusinessFinancialController.java index d0ae8ebb4..177fcec15 100644 --- a/jsowell-admin/src/main/java/com/jsowell/api/uniapp/business/BusinessFinancialController.java +++ b/jsowell-admin/src/main/java/com/jsowell/api/uniapp/business/BusinessFinancialController.java @@ -12,10 +12,12 @@ import com.jsowell.pile.dto.business.BusinessEfficiencyQueryDTO; import com.jsowell.pile.dto.business.BusinessOperationAnalysisQueryDTO; import com.jsowell.pile.dto.business.BusinessScaleQueryDTO; 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.BusinessGunEfficiencyAnalysisVO; import com.jsowell.pile.vo.uniapp.business.BusinessOperationAnalysisVO; import com.jsowell.pile.vo.uniapp.business.BusinessScaleVO; +import com.jsowell.pile.vo.uniapp.business.BusinessStationRankVO; import com.jsowell.pile.vo.web.MerchantOrderReportVO; import org.apache.commons.lang3.StringUtils; 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.RestController; +import java.util.List; + /** * 运营端财务信息相关Controller * @@ -178,4 +182,60 @@ public class BusinessFinancialController extends BaseController { } 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 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; + } } diff --git a/jsowell-pile/src/main/java/com/jsowell/pile/service/BusinessFinancialService.java b/jsowell-pile/src/main/java/com/jsowell/pile/service/BusinessFinancialService.java index ce5dfb16d..487c4655d 100644 --- a/jsowell-pile/src/main/java/com/jsowell/pile/service/BusinessFinancialService.java +++ b/jsowell-pile/src/main/java/com/jsowell/pile/service/BusinessFinancialService.java @@ -6,13 +6,17 @@ import com.jsowell.pile.dto.ParkingCouponRecordQueryDTO; import com.jsowell.pile.dto.business.BusinessOperationAnalysisQueryDTO; import com.jsowell.pile.dto.business.BusinessEfficiencyQueryDTO; 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.BusinessGunEfficiencyAnalysisVO; import com.jsowell.pile.vo.uniapp.business.BusinessOperationAnalysisVO; 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.ParkingCouponRecordVO; +import java.util.List; + public interface BusinessFinancialService { MerchantOrderReportVO getMyWallet(MerchantOrderReportDTO dto); @@ -55,4 +59,20 @@ public interface BusinessFinancialService { * @return 经营效率数据(含指标卡片和曲线图) */ BusinessEfficiencyVO getBusinessEfficiency(BusinessEfficiencyQueryDTO dto); + + /** + * 查询场站订单排行 + * + * @param dto 查询条件 + * @return 场站订单排行列表(按订单数量降序) + */ + List getStationOrderRank(BusinessOperationAnalysisQueryDTO dto); + + /** + * 查询效率分析(单均效率 + 枪均效率) + * + * @param dto 查询条件 + * @return 效率分析数据(含单均效率和枪均效率两个维度) + */ + BusinessEfficiencyAnalysisVO getEfficiencyAnalysis(BusinessOperationAnalysisQueryDTO dto); } diff --git a/jsowell-pile/src/main/java/com/jsowell/pile/service/impl/BusinessFinancialServiceImpl.java b/jsowell-pile/src/main/java/com/jsowell/pile/service/impl/BusinessFinancialServiceImpl.java index cd1b2c2d8..7dd06f6d7 100644 --- a/jsowell-pile/src/main/java/com/jsowell/pile/service/impl/BusinessFinancialServiceImpl.java +++ b/jsowell-pile/src/main/java/com/jsowell/pile/service/impl/BusinessFinancialServiceImpl.java @@ -28,6 +28,7 @@ import com.jsowell.pile.service.PileStationInfoService; import com.jsowell.pile.service.SettleOrderReportService; import com.jsowell.pile.util.UserUtils; 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.BusinessEfficiencyVO; 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.BusinessScaleMetricVO; 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.ParkingCouponRecordVO; 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 stationIdList = resolveStationIds(dto.getStationIdList()); + + // 并行查询订单汇总和枪口数量 + CompletableFuture summaryFuture = CompletableFuture.supplyAsync( + () -> buildSummaryFromReports( + queryRawReports(stationIdList, dto.getStartTime(), dto.getEndTime())), + FINANCIAL_THREAD_POOL); + CompletableFuture 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 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 stationIdList = resolveStationIds(dto.getStationIdList()); + + // 查询结算报表原始数据 + List reportList = queryRawReports( + stationIdList, dto.getStartTime(), dto.getEndTime()); + + if (CollectionUtils.isEmpty(reportList)) { + return new ArrayList<>(); + } + + // 按站点ID分组,累加订单数量 + Map 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 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 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; + } + /** * 查询经营效率 * 优化:当前周期和上周期汇总并行查询,枪口数量与总额定功率并行查询 diff --git a/jsowell-pile/src/main/java/com/jsowell/pile/vo/uniapp/business/BusinessEfficiencyAnalysisVO.java b/jsowell-pile/src/main/java/com/jsowell/pile/vo/uniapp/business/BusinessEfficiencyAnalysisVO.java new file mode 100644 index 000000000..256a4ef2c --- /dev/null +++ b/jsowell-pile/src/main/java/com/jsowell/pile/vo/uniapp/business/BusinessEfficiencyAnalysisVO.java @@ -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; +} diff --git a/jsowell-pile/src/main/java/com/jsowell/pile/vo/uniapp/business/BusinessStationRankVO.java b/jsowell-pile/src/main/java/com/jsowell/pile/vo/uniapp/business/BusinessStationRankVO.java new file mode 100644 index 000000000..48d97ce19 --- /dev/null +++ b/jsowell-pile/src/main/java/com/jsowell/pile/vo/uniapp/business/BusinessStationRankVO.java @@ -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; +} From 9a6ec3e79251a4a629bca8bad36117b963622b5f Mon Sep 17 00:00:00 2001 From: Lemon Date: Mon, 25 May 2026 13:33:35 +0800 Subject: [PATCH 5/5] =?UTF-8?q?update=20=E5=88=86=E9=A1=B5=E6=9F=A5?= =?UTF-8?q?=E8=AF=A2=E5=9C=BA=E7=AB=99=E8=AE=A2=E5=8D=95=E6=8E=92=E8=A1=8C?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../business/BusinessFinancialController.java | 18 +++---- .../BusinessOperationAnalysisQueryDTO.java | 10 ++++ .../service/BusinessFinancialService.java | 11 ++-- .../impl/BusinessFinancialServiceImpl.java | 54 +++++++++++-------- 4 files changed, 54 insertions(+), 39 deletions(-) diff --git a/jsowell-admin/src/main/java/com/jsowell/api/uniapp/business/BusinessFinancialController.java b/jsowell-admin/src/main/java/com/jsowell/api/uniapp/business/BusinessFinancialController.java index 177fcec15..c3dbf5f90 100644 --- a/jsowell-admin/src/main/java/com/jsowell/api/uniapp/business/BusinessFinancialController.java +++ b/jsowell-admin/src/main/java/com/jsowell/api/uniapp/business/BusinessFinancialController.java @@ -6,6 +6,7 @@ import com.jsowell.common.core.page.PageResponse; import com.jsowell.common.enums.ykc.ReturnCodeEnum; import com.jsowell.common.exception.BusinessException; import com.jsowell.common.response.RestApiResponse; +import com.google.common.collect.ImmutableMap; import com.jsowell.pile.dto.MerchantOrderReportDTO; import com.jsowell.pile.dto.ParkingCouponRecordQueryDTO; import com.jsowell.pile.dto.business.BusinessEfficiencyQueryDTO; @@ -17,7 +18,6 @@ import com.jsowell.pile.vo.uniapp.business.BusinessEfficiencyVO; import com.jsowell.pile.vo.uniapp.business.BusinessGunEfficiencyAnalysisVO; import com.jsowell.pile.vo.uniapp.business.BusinessOperationAnalysisVO; import com.jsowell.pile.vo.uniapp.business.BusinessScaleVO; -import com.jsowell.pile.vo.uniapp.business.BusinessStationRankVO; import com.jsowell.pile.vo.web.MerchantOrderReportVO; import org.apache.commons.lang3.StringUtils; import org.springframework.beans.factory.annotation.Autowired; @@ -26,8 +26,6 @@ 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; - /** * 运营端财务信息相关Controller * @@ -212,10 +210,10 @@ public class BusinessFinancialController extends BaseController { } /** - * 查询场站订单排行 + * 分页查询场站订单排行 * - * @param dto 查询参数 - * @return 场站订单排行列表(按订单数量降序) + * @param dto 查询参数(含pageNum、pageSize) + * @return 分页结果(场站订单排行列表,按订单数量降序) */ @PostMapping("/stationOrderRank") public RestApiResponse getStationOrderRank(@RequestBody BusinessOperationAnalysisQueryDTO dto) { @@ -225,10 +223,10 @@ public class BusinessFinancialController extends BaseController { if (dto == null) { throw new BusinessException(ReturnCodeEnum.CODE_PARAM_NOT_NULL_ERROR); } - List result = businessFinancialService.getStationOrderRank(dto); - response = new RestApiResponse<>(result); - logger.info("查询场站订单排行成功 startTime:{}, endTime:{}, 站点数量:{}", - dto.getStartTime(), dto.getEndTime(), result.size()); + PageResponse pageResponse = businessFinancialService.getStationOrderRank(dto); + response = new RestApiResponse<>(ImmutableMap.of("pageResponse", pageResponse)); + logger.info("查询场站订单排行成功 startTime:{}, endTime:{}, total:{}", + dto.getStartTime(), dto.getEndTime(), pageResponse.getTotal()); } catch (BusinessException e) { logger.warn("查询场站订单排行业务异常 code:{}, message:{}", e.getCode(), e.getMessage(), e); response = new RestApiResponse<>(e.getCode(), e.getMessage()); diff --git a/jsowell-pile/src/main/java/com/jsowell/pile/dto/business/BusinessOperationAnalysisQueryDTO.java b/jsowell-pile/src/main/java/com/jsowell/pile/dto/business/BusinessOperationAnalysisQueryDTO.java index e172e2891..0fb35717a 100644 --- a/jsowell-pile/src/main/java/com/jsowell/pile/dto/business/BusinessOperationAnalysisQueryDTO.java +++ b/jsowell-pile/src/main/java/com/jsowell/pile/dto/business/BusinessOperationAnalysisQueryDTO.java @@ -38,4 +38,14 @@ public class BusinessOperationAnalysisQueryDTO { * 当前选中的指标编码 */ private String selectedMetricCode; + + /** + * 页码(用于场站排行分页) + */ + private Integer pageNum; + + /** + * 每页条数(用于场站排行分页) + */ + private Integer pageSize; } diff --git a/jsowell-pile/src/main/java/com/jsowell/pile/service/BusinessFinancialService.java b/jsowell-pile/src/main/java/com/jsowell/pile/service/BusinessFinancialService.java index 487c4655d..87fb249f6 100644 --- a/jsowell-pile/src/main/java/com/jsowell/pile/service/BusinessFinancialService.java +++ b/jsowell-pile/src/main/java/com/jsowell/pile/service/BusinessFinancialService.java @@ -11,12 +11,9 @@ import com.jsowell.pile.vo.uniapp.business.BusinessEfficiencyVO; import com.jsowell.pile.vo.uniapp.business.BusinessGunEfficiencyAnalysisVO; import com.jsowell.pile.vo.uniapp.business.BusinessOperationAnalysisVO; 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.ParkingCouponRecordVO; -import java.util.List; - public interface BusinessFinancialService { MerchantOrderReportVO getMyWallet(MerchantOrderReportDTO dto); @@ -61,12 +58,12 @@ public interface BusinessFinancialService { BusinessEfficiencyVO getBusinessEfficiency(BusinessEfficiencyQueryDTO dto); /** - * 查询场站订单排行 + * 分页查询场站订单排行 * - * @param dto 查询条件 - * @return 场站订单排行列表(按订单数量降序) + * @param dto 查询条件(含pageNum、pageSize) + * @return 分页结果(场站订单排行列表,按订单数量降序) */ - List getStationOrderRank(BusinessOperationAnalysisQueryDTO dto); + PageResponse getStationOrderRank(BusinessOperationAnalysisQueryDTO dto); /** * 查询效率分析(单均效率 + 枪均效率) diff --git a/jsowell-pile/src/main/java/com/jsowell/pile/service/impl/BusinessFinancialServiceImpl.java b/jsowell-pile/src/main/java/com/jsowell/pile/service/impl/BusinessFinancialServiceImpl.java index 7dd06f6d7..a896626e2 100644 --- a/jsowell-pile/src/main/java/com/jsowell/pile/service/impl/BusinessFinancialServiceImpl.java +++ b/jsowell-pile/src/main/java/com/jsowell/pile/service/impl/BusinessFinancialServiceImpl.java @@ -898,16 +898,16 @@ public class BusinessFinancialServiceImpl implements BusinessFinancialService { } /** - * 查询场站订单排行 - * 按站点分组统计订单数量,按订单数量降序排列 + * 分页查询场站订单排行 + * 按站点分组统计订单数量,按订单数量降序排列,支持分页 * - * @param dto 查询条件 - * @return 场站订单排行列表 + * @param dto 查询条件(含pageNum、pageSize) + * @return 分页结果 */ @Override - public List getStationOrderRank(BusinessOperationAnalysisQueryDTO dto) { + public PageResponse getStationOrderRank(BusinessOperationAnalysisQueryDTO dto) { if (dto == null) { - return new ArrayList<>(); + return PageResponse.builder().pageNum(1).pageSize(10).list(new ArrayList<>()).total(0).pages(0).build(); } if (StringUtils.isBlank(dto.getStartTime()) && StringUtils.isBlank(dto.getEndTime())) { LocalDate endDate = LocalDate.now(); @@ -916,6 +916,10 @@ public class BusinessFinancialServiceImpl implements BusinessFinancialService { dto.setEndTime(endDate.toString()); } + // 设置默认分页参数 + int pageNum = dto.getPageNum() != null && dto.getPageNum() > 0 ? dto.getPageNum() : 1; + int pageSize = dto.getPageSize() != null && dto.getPageSize() > 0 ? dto.getPageSize() : 10; + List stationIdList = resolveStationIds(dto.getStationIdList()); // 查询结算报表原始数据 @@ -923,7 +927,7 @@ public class BusinessFinancialServiceImpl implements BusinessFinancialService { stationIdList, dto.getStartTime(), dto.getEndTime()); if (CollectionUtils.isEmpty(reportList)) { - return new ArrayList<>(); + return PageResponse.builder().pageNum(pageNum).pageSize(pageSize).list(new ArrayList<>()).total(0).pages(0).build(); } // 按站点ID分组,累加订单数量 @@ -937,20 +941,11 @@ public class BusinessFinancialServiceImpl implements BusinessFinancialService { stationOrderCountMap.merge(sId, chargeNum, Integer::sum); } - // 批量查询站点名称 + // 批量查询站点名称(一次性查出所有站点,内存中按ID匹配,避免N+1查询) + List allStations = pileStationInfoService.selectPileStationInfoList(new PileStationInfo()); Map 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, "未知站点"); - } + for (PileStationInfo station : allStations) { + stationNameMap.put(String.valueOf(station.getId()), station.getStationName()); } // 按订单数量降序排列并构建排行列表 @@ -965,12 +960,27 @@ public class BusinessFinancialServiceImpl implements BusinessFinancialService { 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; + // 手动分页 + long total = rankList.size(); + int pages = (int) Math.ceil((double) total / pageSize); + int fromIndex = (pageNum - 1) * pageSize; + int toIndex = Math.min(fromIndex + pageSize, rankList.size()); + List pageList = fromIndex < rankList.size() + ? rankList.subList(fromIndex, toIndex) + : new ArrayList<>(); + + return PageResponse.builder() + .pageNum(pageNum) + .pageSize(pageSize) + .list(pageList) + .total(total) + .pages(pages) + .build(); } /**